<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
	<title>codahale.com</title>
	<subtitle>
		Coda Hale lives in Berkeley, CA, where he writes about programming, web
		development, and the occasional bit about bicycles.
	</subtitle>
	
	<link href="http://codahale.com/" />
	<updated>2012-01-25T09:26:32+02:00</updated>
	<id>http://codahale.com/</id>
	<author>
		<name>Coda Hale</name>
		<email>coda.hale@gmail.com</email>
	</author>
	
	<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/codahale" /><feedburner:info uri="codahale" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
		<title>The Rest Of The Story</title>
		<link href="http://feedproxy.google.com/~r/codahale/~3/7pLlVL6mi8U/" />
		<updated>2011-11-29T00:00:00+02:00</updated>
		<id>http://codahale.com/the-rest-of-the-story</id>
		<content type="html">
			&lt;p&gt;About a week ago, I
&lt;a href="http://twitter.com/coda/status/139133458181144576"&gt;mentioned in passing&lt;/a&gt; to an
old co-worker on Twitter that Yammer was moving some of our stack from Scala to
Java. A few days later, Donald Fischer (the CEO of
&lt;a href="http://typesafe.com/"&gt;Typesafe&lt;/a&gt;) emailed me at my personal account, asking for
more details. He CC'ed Martin Odersky, the lead designer of Scala and Typesafe&amp;rsquo;s
Chief Architect. Given that the two people best-situated to improve Scala had
just asked me about my experience over the past two years of using Scala, I
wrote a long, considered, brutally honest
&lt;a href="/downloads/email-to-donald.txt"&gt;response&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the process of composing that email, I asked a few personal friends to review
a draft of it. One of those friends shared that draft with someone else, who
shared it with someone else, etc. etc. and today I woke up to find my email to
Donald and Martin splashed across Hacker News and Twitter. I deleted the gist,
but the cat was out of the bag, and now I find myself having to publicly explain
the context of a private conversation.&lt;/p&gt;

&lt;p&gt;I wrote that email for a very specific reason: Donald asked me for my opinion.
If someone asks me for an honest opinion of them or their work, in private, I
feel morally compelled to be as honest as I can with them. The only way we can
ever know how we &lt;em&gt;appear&lt;/em&gt; to other people is &lt;em&gt;through&lt;/em&gt; other people; the only
way we can know what others think of what we build is to ask and listen to them.
The fundamental asymmetry of consciousness means
&lt;a href="http://en.wikipedia.org/wiki/Johari_window"&gt;triangulation&lt;/a&gt; is the only path to
understanding. Anyone running a business understands this, at some level: what
customers say does not by itself constitute objective reality, but does offer
critical insight into it that one is essentially incapable of discovering by
oneself.&lt;/p&gt;

&lt;p&gt;But it&amp;rsquo;s simplistic and naive to assume that I wrote what I did in an unguarded
moment and that somehow this represents a more truthful account of what I&amp;rsquo;d say
in public. The most that you can possibly know about this is the text of my
email to Donald and Martin, not the context.&lt;/p&gt;

&lt;p&gt;Yes, that email is not what I would say in public. The Scala community needs
another giant blog post about ways in which someone doesn&amp;rsquo;t like Scala like I
need a hole in my head, and I&amp;rsquo;d rather suck a dog&amp;rsquo;s nose dry than lend a hand to
the nerd slapfights on Hacker News. The world has yet to take me aside and ask
me for my opinion of it, and in the past few years I&amp;rsquo;ve found that it&amp;rsquo;s far more
profitable to build things rather than tilt at windmills.&lt;/p&gt;

&lt;p&gt;So.&lt;/p&gt;

&lt;p&gt;Should you use Scala? Is Java better?&lt;/p&gt;

&lt;p&gt;(You&amp;rsquo;re asking the wrong questions.)&lt;/p&gt;

			&lt;p&gt;(This was posted at &lt;a href="http://codahale.com/the-rest-of-the-story/"&gt;codahale.com&lt;/a&gt;.)&lt;/p&gt;
		&lt;img src="http://feeds.feedburner.com/~r/codahale/~4/7pLlVL6mi8U" height="1" width="1"/&gt;</content>
	<feedburner:origLink>http://codahale.com/the-rest-of-the-story/</feedburner:origLink></entry>
	
	<entry>
		<title>You Can’t Sacrifice Partition Tolerance</title>
		<link href="http://feedproxy.google.com/~r/codahale/~3/6TbpeG4M6ik/" />
		<updated>2010-10-07T00:00:00+02:00</updated>
		<id>http://codahale.com/you-cant-sacrifice-partition-tolerance</id>
		<content type="html">
			&lt;p&gt;I&amp;rsquo;ve seen a number of distributed databases recently
&lt;a href="http://danweinreb.org/blog/voltdb-versus-nosql"&gt;describe&lt;/a&gt; themselves as
&lt;a href="http://en.wikipedia.org/w/index.php?title=Membase&amp;amp;oldid=384896988"&gt;being &amp;ldquo;CA&amp;rdquo;&lt;/a&gt;
&amp;mdash;that is, providing both consistency and availability while not providing
partition-tolerance. To me, this indicates that the developers of these systems
do not understand the the CAP theorem and its implications.&lt;/p&gt;

&lt;h2&gt;A Quick Refresher&lt;/h2&gt;

&lt;p&gt;In 2000, Dr. Eric Brewer gave a keynote at the &lt;em&gt;Proceedings of the Annual ACM
Symposium on Principles of Distributed Computing&lt;/em&gt;&lt;a href="#ft1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; in which
he laid out his famous CAP Theorem: &lt;em&gt;a shared-data system can have at most two
of the three following properties: &lt;strong&gt;C&lt;/strong&gt;onsistency, &lt;strong&gt;A&lt;/strong&gt;vailability, and
tolerance to network &lt;strong&gt;P&lt;/strong&gt;artitions.&lt;/em&gt; In 2002, Gilbert and
Lynch&lt;a href="#ft2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; converted &amp;ldquo;Brewer&amp;rsquo;s conjecture&amp;rdquo; into a more formal
definition with an informal proof. As far as I can tell, it&amp;rsquo;s been misunderstood
ever since.&lt;/p&gt;

&lt;p&gt;So let&amp;rsquo;s be clear on the terms we&amp;rsquo;re using.&lt;/p&gt;

&lt;h2&gt;On Consistency&lt;/h2&gt;

&lt;p&gt;From Gilbert and Lynch&lt;a href="#ft2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Atomic, or linearizable, consistency is the condition expected by most web
services today. Under this consistency guarantee, there must exist a total
order on all operations such that each operation looks as if it were completed
at a single instant. This is equivalent to requiring requests of the
distributed shared memory to act as if they were executing on a single node,
responding to operations one at a time.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Most people seem to understand this, but it bears repetition: a system is
consistent if an update is applied to all relevant nodes at the same logical
time. Among other things, this means that standard database replication is
&lt;em&gt;not strongly consistent.&lt;/em&gt; As anyone whose read replicas have drifted from the
master knows, special logic must be introduced to handle replication lag.&lt;/p&gt;

&lt;p&gt;That said, consistency which is both instantaneous and global is impossible. The
universe simply does not permit it. So the goal here is to push the time
resolutions at which the consistency breaks down to a point where we no longer
notice it. Just don&amp;rsquo;t try to act outside your own light cone…&lt;/p&gt;

&lt;h2&gt;On Availability&lt;/h2&gt;

&lt;p&gt;Again from Gilbert and Lynch&lt;a href="#ft2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;For a distributed system to be continuously available, every request received
by a non-failing node in the system must result in a response. That is, any
algorithm used by the service must eventually terminate … [When] qualified by
the need for partition tolerance, this can be seen as a strong definition of
availability: even when severe network failures occur, every request must
terminate.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Despite the notion of &lt;a href="http://blog.mongodb.org/post/381927266/what-about-durability"&gt;&amp;ldquo;100% uptime as much as possible,&amp;rdquo;&lt;/a&gt;
there are limits to availability. If you have a single piece of data on five
nodes and all five nodes die, that data is gone and any request which required
it in order to be processed cannot be handled.&lt;/p&gt;

&lt;p&gt;(N.B.: A &lt;code&gt;500 The Bees They're In My Eyes&lt;/code&gt; response does not count as an actual
response any more than a network timeout does. A response contains the results
of the requested work.)&lt;/p&gt;

&lt;h2&gt;On Partition Tolerance&lt;/h2&gt;

&lt;p&gt;Once more, Gilbert and Lynch&lt;a href="#ft2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;In order to model partition tolerance, the network will be allowed to lose
arbitrarily many messages sent from one node to another. When a network is
partitioned, all messages sent from nodes in one component of the partition to
nodes in another component are lost. (And any pattern of message loss can be
modeled as a temporary partition separating the communicating nodes at the
exact instant the message is lost.)&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;This seems to be the part that most people misunderstand.&lt;/p&gt;

&lt;p&gt;Some systems cannot be partitioned. Single-node systems (e.g., a monolithic
Oracle server with no replication) are incapable of experiencing a network
partition. But practically speaking these are rare; add remote clients to the
monolithic Oracle server and you get a distributed system which &lt;em&gt;can&lt;/em&gt; experience
a network partition (e.g., the Oracle server becomes unavailable).&lt;/p&gt;

&lt;p&gt;Network partitions aren&amp;rsquo;t limited to dropped packets: a crashed server can be
thought of as a network partition. The failed node is effectively the only
member of its partition component, and thus all messages to it are &amp;ldquo;lost&amp;rdquo; (i.e.,
they are not processed by the node due to its failure). Handling a crashed
machine counts as partition-tolerance.
(&lt;strong&gt;Update: I was wrong about this part. See &lt;a href="#errata10221010"&gt;this&lt;/a&gt; for more.&lt;/strong&gt;)
(N.B.: A node which has gone offline is actually the easiest sort of failure to
deal with—you&amp;rsquo;re assured that the dead node is not giving incorrect responses to
another component of your system.)&lt;/p&gt;

&lt;p&gt;For a distributed (i.e., multi-node) system to &lt;strong&gt;not&lt;/strong&gt; require
partition-tolerance it would have to run on a network which is &lt;em&gt;guaranteed to
never drop messages&lt;/em&gt; (or even deliver them late) and whose nodes are &lt;em&gt;guaranteed
to never die&lt;/em&gt;. You and I do not work with these types of systems because &lt;strong&gt;they
don&amp;rsquo;t exist.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;Given A System In Which Failure Is An Option&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://voltdb.com/voltdb-webinar-sql-urban-myths"&gt;Michael Stonebraker&amp;rsquo;s assertions&lt;/a&gt;
aside, partitions (read: failures) do happen, and the chances that any one of
your nodes will fail jumps exponentially as the number of nodes increases:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P(any failure) = 1 &amp;ndash; P(individual node not failing)&lt;sup&gt;number of nodes&lt;/sup&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If a single node has a 99.9% chance of not failing in a particular time period,
a cluster of 40 has a 96.1% chance not failing. In other words, you&amp;rsquo;ve got
around a 4% chance that &lt;em&gt;something&lt;/em&gt; will go wrong. (And this is assuming that
your failures are unrelated; in reality, they tend to cascade.)&lt;/p&gt;

&lt;p&gt;Therefore, the question you should be asking yourself is:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;In the event of failures, which will this system sacrifice? Consistency or
availability?&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2&gt;Choosing Consistency Over Availability&lt;/h2&gt;

&lt;p&gt;If a system chooses to provide Consistency over Availability in the presence of
partitions (again, read: failures), it will preserve the guarantees of its
atomic reads and writes by refusing to respond to some requests. It may decide
to shut down entirely (like the clients of a single-node data store), refuse
writes (like Two-Phase Commit), or only respond to reads and writes for pieces
of data whose &amp;ldquo;master&amp;rdquo; node is inside the partition component (like Membase).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is perfectly reasonable.&lt;/em&gt; There are plenty of things (atomic counters, for
one) which are made much easier (or even possible) by strongly consistent
systems. They are a perfectly valid type of tool for satisfying a particular set
of business requirements.&lt;/p&gt;

&lt;h2&gt;Choosing Availability Over Consistency&lt;/h2&gt;

&lt;p&gt;If a system chooses to provide Availability over Consistency in the presence
of partitions (all together now: failures), it will respond to all requests,
potentially returning stale reads and accepting conflicting writes. These
inconsistencies are often resolved via causal ordering mechanisms like vector
clocks and application-specific conflict resolution procedures. (Dynamo systems
usually offer both of these; Cassandra&amp;rsquo;s hard-coded Last-Writer-Wins conflict
resolution being the main exception.)&lt;/p&gt;

&lt;p&gt;Again, &lt;em&gt;this is perfectly reasonable.&lt;/em&gt; There are plenty of data models which are
amenable to conflict resolution and for which stale reads are acceptable
(ironically, many of these data models are in the financial industry) and for
which unavailability results in massive bottom-line losses. (Amazon&amp;rsquo;s shopping
cart system is the canonical example of a Dynamo model&lt;a href="#ft3"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;But Never Both&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You cannot, however, choose both consistency and availability in a distributed
system.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a thought experiment, imagine a distributed system which keeps track of a
single piece of data using three nodes—&lt;code&gt;A&lt;/code&gt;, &lt;code&gt;B&lt;/code&gt;, and &lt;code&gt;C&lt;/code&gt;—and which claims to be
both consistent and available in the face of network partitions. Misfortune
strikes, and that system is partitioned into two components: &lt;code&gt;{A,B}&lt;/code&gt; and &lt;code&gt;{C}&lt;/code&gt;.
In this state, a write request arrives at node &lt;code&gt;C&lt;/code&gt; to update the single piece of
data.&lt;/p&gt;

&lt;p&gt;That node only has two options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Accept the write, knowing that neither &lt;code&gt;A&lt;/code&gt; nor &lt;code&gt;B&lt;/code&gt; will know about this new
data until the partition heals.&lt;/li&gt;
&lt;li&gt;Refuse the write, knowing that the client might not be able to contact &lt;code&gt;A&lt;/code&gt; or
&lt;code&gt;B&lt;/code&gt; until the partition heals.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;You either choose availability (Door #1) or you choose consistency (Door #2).
You cannot choose both.&lt;/p&gt;

&lt;p&gt;To claim to do so is claiming either that the system operates on a single node
(and is therefore not distributed) or that an update applied to a node in one
component of a network partition will also be applied to another node in a
different partition component &lt;strong&gt;&lt;em&gt;magically&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is, as you might imagine, rarely true.&lt;/p&gt;

&lt;h2&gt;A Readjustment In Focus&lt;/h2&gt;

&lt;p&gt;I think part of the problem with practical interpretations of the CAP theorem,
especially with Gilbert and Lynch&amp;rsquo;s formulation, is the fact that most real
distributed systems do not require atomic consistency or perfect availability
and will never be called upon to perform on a network suffering from arbitrary
message loss. Consistency, Availability, and Partition Tolerance are the
Platonic ideals of a distributed system&amp;mdash;we can partake of them enough to meet
business requirements, but the nature of reality is such that there will always
be compromises.&lt;/p&gt;

&lt;p&gt;When it comes to designing or evaluating distributed systems, then, I think we
should focus less on which two of the three Virtues we like most and more on
what compromises a system makes as things go bad. (Because they will
&lt;a href="http://blog.foursquare.com/2010/10/05/so-that-was-a-bummer/"&gt;go bad&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;This brings us to an earlier bit of Brewer wisdom: &lt;strong&gt;yield&lt;/strong&gt; and &lt;strong&gt;harvest&lt;/strong&gt;,
which come from Fox and Brewer&amp;rsquo;s &amp;ldquo;Harvest, Yield, and Scalable Tolerant
Systems&amp;rdquo;&lt;a href="#ft4"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;We assume that clients make queries to servers, in which case there are at
least two metrics for correct behavior: &lt;strong&gt;yield&lt;/strong&gt;, which is the probability of
completing a request, and &lt;strong&gt;harvest&lt;/strong&gt;, which measures the fraction of the data
reflected in the response, i.e. the completeness of the answer to the query.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2&gt;On Yield&lt;/h2&gt;

&lt;p&gt;In a later article&lt;a href="#ft5"&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt;, Brewer expands on &lt;strong&gt;yield&lt;/strong&gt; and its
uses:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Numerically, this is typically very close to uptime, but it is more useful in
practice because it directly maps to user experience and because it correctly
reflects that not all seconds have equal value. Being down for a second when
there are no queries has no impact on users or yield, but reduces uptime.
Similarly, being down for one second at peak and off-peak times generates the
same uptime, but vastly different yields because there might be an
order-of-magnitude difference in load between the peak second and the
minimum-load second. Thus we focus on yield rather than uptime.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2&gt;On Harvest&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Harvest&lt;/strong&gt; is a far more overlooked metric, especially in the age of the
relational database. If we imagine working on a search engine, however, we can
imagine there being separate indexes for each word. The index of web pages which
use the word &amp;ldquo;cute&amp;rdquo; is on node &lt;code&gt;A&lt;/code&gt;, the index of web pages which use the word
&amp;ldquo;baby&amp;rdquo; is on node &lt;code&gt;B&lt;/code&gt;, and the index for the word &amp;ldquo;animals&amp;rdquo; is on machine &lt;code&gt;C&lt;/code&gt;. A
search, then, for &amp;ldquo;cute baby animals&amp;rdquo; which combined results from nodes &lt;code&gt;A&lt;/code&gt;,
&lt;code&gt;B&lt;/code&gt;, and &lt;code&gt;C&lt;/code&gt; would have a 100% harvest. If node&lt;code&gt;B&lt;/code&gt; was unavailable, however, we
might  return a result for just &amp;ldquo;cute animals,&amp;rdquo; which would be a harvest of 66%.
In other words:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;harvest = data available/complete data&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Another example would be a system which stores versions of documents. In the
event that some nodes are down, the system could choose to present the most
recent version of a document that it could find, even if it knew there was a
probability that it was not the most recent version it had stored.&lt;/p&gt;

&lt;h2&gt;A Better Heuristic&lt;/h2&gt;

&lt;p&gt;Whether a system favors yield or harvest (or is even &lt;em&gt;capable&lt;/em&gt; of reducing
harvest) tends to be an outcome of its design.&lt;/p&gt;

&lt;p&gt;As Brewer puts it&lt;a href="#ft5"&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;The key insight is that we can influence whether faults impact yield, harvest,
or both. Replicated systems tend to map faults to reduced capacity (and to
yield at high utilizations), while partitioned systems tend to map faults to
reduced harvest, as parts of the database temporarily disappear, but the
capacity in queries per second remains the same.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;In terms of general advice to people building distributed systems (and really,
who isn&amp;rsquo;t these days?), I think the following is far more effective:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Despite your best efforts, your system will experience enough faults that it
will have to make a choice between reducing yield (i.e., stop answering
requests) and reducing harvest (i.e., giving answers based on incomplete
data). This decision should be based on business requirements.&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2&gt;Well Now What&lt;/h2&gt;

&lt;p&gt;It&amp;rsquo;s incredibly unlikely this will change the way people will build distributed
systems—far more of our motivation comes from business concerns (&amp;ldquo;our shopping
carts &lt;em&gt;cannot&lt;/em&gt; go down&amp;rdquo; or &amp;ldquo;there would be no way for us to reconcile this
later&amp;rdquo;). What I&amp;rsquo;d like to see, though, is far fewer people unknowingly
describing their systems as logical impossibilities.&lt;/p&gt;

&lt;h2&gt;tl;dr&lt;/h2&gt;

&lt;p&gt;Of the CAP theorem&amp;rsquo;s Consistency, Availability, and Partition Tolerance,
Partition Tolerance is mandatory in distributed systems. You cannot &lt;strong&gt;not&lt;/strong&gt;
choose it. Instead of CAP, you should think about your availability in terms of
&lt;em&gt;yield&lt;/em&gt; (percent of requests answered successfully) and &lt;em&gt;harvest&lt;/em&gt; (percent of
required data actually included in the responses) and which of these two your
system will sacrifice when failures happen.&lt;/p&gt;

&lt;h2&gt;References (i.e., Things You Should Read)&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Brewer. &lt;a href="http://www.cs.berkeley.edu/~brewer/cs262b-2004/PODC-keynote.pdf"&gt;Towards robust distributed systems.&lt;/a&gt;
Proceedings of the Annual ACM Symposium on Principles of Distributed
Computing (2000) vol. 19 pp. 7-10 &lt;a id="ft1" /&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gilbert and Lynch. &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.67.6951&amp;amp;rep=rep1&amp;amp;type=pdf"&gt;Brewer&amp;rsquo;s conjecture and the feasibility of consistent, available, partition-tolerant web services.&lt;/a&gt;
ACM SIGACT News (2002) vol. 33 (2) pp. 59 &lt;a id="ft2" /&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DeCandia et al. &lt;a href="http://s3.amazonaws.com/AllThingsDistributed/sosp/amazon-dynamo-sosp2007.pdf"&gt;Dynamo: Amazon&amp;rsquo;s highly available key-value store.&lt;/a&gt;
SOSP &amp;lsquo;07: Proceedings of twenty-first ACM SIGOPS symposium on Operating
systems principles (2007) &lt;a id="ft3" /&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fox and Brewer. &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.24.3690&amp;amp;rep=rep1&amp;amp;type=pdf"&gt;Harvest, yield, and scalable tolerant systems.&lt;/a&gt;
Hot Topics in Operating Systems, 1999. Proceedings of the Seventh Workshop on
(1999) pp. 174 &amp;ndash; 178 &lt;a id="ft4" /&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Brewer. &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.83.4274&amp;amp;rep=rep1&amp;amp;type=pdf"&gt;Lessons from giant-scale services.&lt;/a&gt;
Internet Computing, IEEE (2001) vol. 5 (4) pp. 46 &amp;ndash; 55 &lt;a id="ft5"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;(As a sad postscript: most of the theoretical papers I&amp;rsquo;ve referenced are about a
decade old and all of them are freely available online.)&lt;/p&gt;

&lt;h2&gt;Updated October 8, 2010&lt;/h2&gt;

&lt;p&gt;Dr. Brewer &lt;a href="http://twitter.com/eric_brewer/status/26819094612"&gt;approves&lt;/a&gt; (somewhat).&lt;/p&gt;

&lt;h2&gt;Updated October 21, 2010&lt;/h2&gt;

&lt;p&gt;Dr. Stonebraker &lt;a href="http://voltdb.com/blog/clarifications-cap-theorem-and-data-related-errors"&gt;does not approve&lt;/a&gt; (somehwat).&lt;/p&gt;

&lt;h2&gt;Updated October 22, 2010&lt;/h2&gt;

&lt;p&gt;&lt;a id="errata10221010"&gt;&lt;/a&gt;In his response, Dr. Stonebraker says:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;In Coda’s view, the dead node is in one partition and the remaining N-1 nodes
are in the other one.  The guidance from the CAP theorem is that you must
choose either A or C, when a network partition is present.  As is obvious in
the real world, it is possible to achieve both C and A in this failure mode.
You simply failover to a replica in a transactionally consistent way. Notably,
at least Tandem and Vertica have been doing exactly this for years. Therefore,
considering a node failure as a partition results in an obviously
inappropriate CAP theorem conclusion.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;He is correct: a dead (or wholly partitioned) node can receive no requests, and
so the other nodes can easily compensate without compromising consistency or
availability here. My error lies in forgetting that Gilbert and Lynch&amp;rsquo;s
formulation of availability requires only non-failing nodes to respond, and that
without ≥1 live nodes in a partition there isn&amp;rsquo;t the option for split-brain
syndrome. I regret the error and thank both him and Dr. Brewer for pointing this
out.&lt;/p&gt;

&lt;p&gt;That said, Dr. Stonebraker&amp;rsquo;s assertion that &amp;ldquo;surviving [partitions] will not
&amp;lsquo;move the needle&amp;rsquo; on availability because higher frequency events will cause
global outages&amp;rdquo; is wrong. Multi-node failures may be rarer than single-node
failures, but they are still common enough to have serious effects on business.
In my limited experience I&amp;rsquo;ve dealt with long-lived network partitions in a
single data center (DC), PDU failures, switch failures, accidental power cycles
of whole racks, whole-DC backbone failures, whole-DC power failures, and a
hypoglycemic driver smashing his Ford pickup truck into a DC&amp;rsquo;s HVAC system. And
I&amp;rsquo;m not even an ops guy.&lt;/p&gt;

&lt;p&gt;The fact of the matter is that most real-world systems require substantially
less in the way of consistency guarantees than they do in the way of
availability guarantees. Amazon&amp;rsquo;s shopping carts, for example, do not require
the full ACID treatment, nor do Twitter&amp;rsquo;s timelines or Facebook&amp;rsquo;s news feeds or
Google&amp;rsquo;s indexes. Even the canonical example of an isolated transaction&amp;mdash;a
transfer of funds between bank accounts&amp;mdash;happens with a 24-hour window of
indeterminacy. In fact, one of the few financial transactions which actually
resembles a database transaction is the physical exchange of cash for goods&amp;mdash;a
totally analog experience.&lt;/p&gt;

&lt;p&gt;But whereas failures of consistency are tolerated or even expected, just about
every failure of availability means lost money. Every failed Google search means
fewer ads served and advertisers charged; every item a user can&amp;rsquo;t add to their
shopping cart means fewer items sold; every unprocessed credit charge risks a
regulatory fine. The choice of availability over consistency is a business
choice, not a technical one.&lt;/p&gt;

&lt;p&gt;Given this economic context, it becomes clear why most practitioners at any
interesting scale meet their business needs using highly-available, eventually
consistent systems.&lt;/p&gt;

			&lt;p&gt;(This was posted at &lt;a href="http://codahale.com/you-cant-sacrifice-partition-tolerance/"&gt;codahale.com&lt;/a&gt;.)&lt;/p&gt;
		&lt;img src="http://feeds.feedburner.com/~r/codahale/~4/6TbpeG4M6ik" height="1" width="1"/&gt;</content>
	<feedburner:origLink>http://codahale.com/you-cant-sacrifice-partition-tolerance/</feedburner:origLink></entry>
	
	<entry>
		<title>How To Safely Store A Password</title>
		<link href="http://feedproxy.google.com/~r/codahale/~3/E74EfKexW0E/" />
		<updated>2010-01-31T00:00:00+02:00</updated>
		<id>http://codahale.com/how-to-safely-store-a-password</id>
		<content type="html">
			&lt;h2&gt;Use &lt;code&gt;bcrypt&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Use &lt;a href="http://www.usenix.org/events/usenix99/provos.html"&gt;bcrypt&lt;/a&gt;.
Use &lt;a href="https://github.com/codahale/bcrypt-ruby"&gt;bcrypt&lt;/a&gt;.
Use &lt;a href="http://pypi.python.org/pypi/py-bcrypt/"&gt;bcrypt&lt;/a&gt;.
Use &lt;a href="http://derekslager.com/blog/posts/2007/10/bcrypt-dotnet-strong-password-hashing-for-dotnet-and-mono.ashx"&gt;bcrypt&lt;/a&gt;.
Use &lt;a href="http://www.mindrot.org/projects/jBCrypt/"&gt;bcrypt&lt;/a&gt;.
Use &lt;a href="http://p3rl.org/Authen::Passphrase::BlowfishCrypt"&gt;bcrypt&lt;/a&gt;.
Use &lt;a href="http://www.openwall.com/crypt/"&gt;bcrypt&lt;/a&gt;.
Use &lt;a href="http://www.openwall.com/phpass/"&gt;bcrypt&lt;/a&gt;.
Use &lt;a href="https://github.com/smarkets/erlang-bcrypt"&gt;bcrypt&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Why Not {&lt;code&gt;MD5&lt;/code&gt;, &lt;code&gt;SHA1&lt;/code&gt;, &lt;code&gt;SHA256&lt;/code&gt;, &lt;code&gt;SHA512&lt;/code&gt;, &lt;code&gt;SHA-3&lt;/code&gt;, etc}?&lt;/h2&gt;

&lt;p&gt;These are all &lt;em&gt;general purpose&lt;/em&gt; hash functions, designed to calculate a digest
of huge amounts of data in as short a time as possible. This means that they are
fantastic for ensuring the integrity of data and utterly rubbish for storing
passwords.&lt;/p&gt;

&lt;p&gt;A modern server can calculate the MD5 hash of about
&lt;a href="http://www.cryptopp.com/benchmarks-amd64.html"&gt;330MB every second&lt;/a&gt;. If your
users have passwords which are lowercase, alphanumeric, and 6 characters long,
you can try &lt;em&gt;every single possible password of that size&lt;/em&gt; in around
&lt;strong&gt;40 seconds&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And that&amp;rsquo;s without investing anything.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;re willing to spend about 2,000 USD and a week or two picking up
&lt;a href="http://www.nvidia.com/object/cuda_home.html"&gt;CUDA&lt;/a&gt;, you can put together your
own little supercomputer cluster which will let you
&lt;a href="http://www.win.tue.nl/cccc/sha-1-challenge.html"&gt;try around 700,000,000 passwords a second&lt;/a&gt;.
And that rate you&amp;rsquo;ll be cracking those passwords at the rate of more than &lt;strong&gt;one
per second.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;Salts Will Not Help You&lt;/h2&gt;

&lt;p&gt;It&amp;rsquo;s important to note that &lt;strong&gt;salts are useless for preventing dictionary
attacks or brute force attacks.&lt;/strong&gt; You can use huge salts or many salts or
hand-harvested, shade-grown, organic &lt;a href="http://en.wikipedia.org/wiki/Himalayan_salt"&gt;Himalayan pink salt&lt;/a&gt;.
It doesn&amp;rsquo;t affect how fast an attacker can try a candidate password, given the
hash and the salt from your database.&lt;/p&gt;

&lt;p&gt;Salt or no, if you&amp;rsquo;re using a general-purpose hash function designed for speed
you&amp;rsquo;re well and truly effed.&lt;/p&gt;

&lt;h2&gt;&lt;code&gt;bcrypt&lt;/code&gt; Solves These Problems&lt;/h2&gt;

&lt;p&gt;How? Basically, it&amp;rsquo;s slow as hell. It uses a variant of the Blowfish
encryption algorithm&amp;rsquo;s keying schedule, and introduces a &lt;em&gt;work factor&lt;/em&gt;, which
allows you to determine how expensive the hash function will be. Because of
this, &lt;code&gt;bcrypt&lt;/code&gt; can keep up with Moore&amp;rsquo;s law. As computers get faster you can
increase the work factor and the hash will get slower.&lt;/p&gt;

&lt;p&gt;How much slower is &lt;code&gt;bcrypt&lt;/code&gt; than, say, &lt;code&gt;MD5&lt;/code&gt;? Depends on the work factor. Using
a work factor of 12, &lt;code&gt;bcrypt&lt;/code&gt; hashes the password &lt;code&gt;yaaa&lt;/code&gt; in about 0.3 seconds on
my laptop. &lt;code&gt;MD5&lt;/code&gt;, on the other hand, takes less than a microsecond.&lt;/p&gt;

&lt;p&gt;So we&amp;rsquo;re talking about &lt;strong&gt;5 or so orders of magnitude&lt;/strong&gt;. Instead of cracking a
password every 40 seconds, I&amp;rsquo;d be cracking them every &lt;strong&gt;12 years&lt;/strong&gt; or so. Your
passwords might not need that kind of security and you might need a faster
comparison algorithm, but &lt;code&gt;bcrypt&lt;/code&gt; allows you to choose your balance of speed
and security. Use it.&lt;/p&gt;

&lt;h2&gt;tl;dr&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;bcrypt&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;Updated February 24th, 2011&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;ve been getting pretty regular emails about this article for the past year, and I figured I&amp;rsquo;d address some of the concerns here rather than have the same conversations over and over again.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Isn&amp;rsquo;t &lt;code&gt;bcrypt&lt;/code&gt; just Blowfish? Where do you store the password?&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Please read the &lt;a href="http://www.usenix.org/events/usenix99/provos.html"&gt;Provos &amp;amp; Mazières paper&lt;/a&gt;. &lt;code&gt;bcrypt&lt;/code&gt; is an adaptive password hashing algorithm which uses the Blowfish keying schedule, not a symmetric encryption algorithm.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;You said salts aren&amp;rsquo;t helpful, but what about rainbow tables? Why would you suggest people not use salts?&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;As the &lt;a href="http://www.usenix.org/events/usenix99/provos.html"&gt;Provos &amp;amp; Mazières paper&lt;/a&gt; describes, &lt;code&gt;bcrypt&lt;/code&gt; has salts built-in to prevent rainbow table attacks. So I&amp;rsquo;m not saying salts are without purpose, I&amp;rsquo;m saying that they don&amp;rsquo;t prevent dictionary or brute force attacks (which they don&amp;rsquo;t).&lt;/p&gt;

&lt;p&gt;Rainbow tables, despite their recent popularity as a subject of blog posts, have not aged gracefully. CUDA/OpenCL implementations of password crackers can leverage the massive amount of parallelism available in GPUs, peaking at &lt;a href="http://www.golubev.com/hashgpu.htm"&gt;billions of candidate passwords a second&lt;/a&gt;. You can literally test all lowercase, alphabetic passwords which are ≤7 characters in less than 2 seconds. And you can now rent the hardware which makes this possible to the tune of &lt;a href="http://aws.amazon.com/ec2/#pricing"&gt;less than $3/hour&lt;/a&gt;. For about $300/hour, you could crack around 500,000,000,000 candidate passwords a second.&lt;/p&gt;

&lt;p&gt;Given this massive shift in the economics of cryptographic attacks, it simply doesn&amp;rsquo;t make sense for anyone to waste terabytes of disk space in the hope that their victim didn&amp;rsquo;t use a salt. It&amp;rsquo;s a lot easier to just crack the passwords. Even a &amp;ldquo;good&amp;rdquo; hashing scheme of &lt;code&gt;SHA256(salt + password)&lt;/code&gt; is still completely vulnerable to these cheap and effective attacks, thus the importance of an adaptive hashing algorithm like &lt;code&gt;bcrypt&lt;/code&gt;.&lt;/p&gt;

			&lt;p&gt;(This was posted at &lt;a href="http://codahale.com/how-to-safely-store-a-password/"&gt;codahale.com&lt;/a&gt;.)&lt;/p&gt;
		&lt;img src="http://feeds.feedburner.com/~r/codahale/~4/E74EfKexW0E" height="1" width="1"/&gt;</content>
	<feedburner:origLink>http://codahale.com/how-to-safely-store-a-password/</feedburner:origLink></entry>
	
	<entry>
		<title>FOSS and Male Privilege</title>
		<link href="http://feedproxy.google.com/~r/codahale/~3/gjqUa5dav4k/" />
		<updated>2009-08-27T00:00:00+02:00</updated>
		<id>http://codahale.com/foss-and-male-privilege</id>
		<content type="html">
			&lt;p&gt;From the comments on the LWN thread,
&lt;a href="http://lwn.net/Articles/348459/"&gt;FSF to host a mini-summit on Women in Free Software&lt;/a&gt;:&lt;/p&gt;

&lt;h2&gt;Bruce Perens&lt;/h2&gt;

&lt;blockquote&gt;&lt;p&gt;Can we say that women aren&amp;rsquo;t joining because they, as a population rather than
as individuals, are not interested? The other alternative would be to say that
men in the field had established mechanisms which were astonishingly effective
at keeping them out even though they really were interested, and which still
stood today.&lt;/p&gt;

&lt;p&gt;…&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;d be a lot more comfortable if I heard it from them, and if they explained
what the mechanisms were and how they were so effective that even people who
were interested were barred from participating with almost total
effectiveness. And why this was not so for a number of other fields.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2&gt;Skud&lt;/h2&gt;

&lt;blockquote&gt;&lt;p&gt;Bruce, I started using Linux in 1993 with slackware installed off a stack of
floppies. I ran X with fvwm and kermit for dialup Internet. I learnt Perl a
couple of years later and have worked professionally and full time with Open
Source (mostly LAMP stack) since 1996. I&amp;rsquo;ve done all-nighters and
adrenaline-fuelled hacking runs and totally fscked my PC with broken kernel
recompiles. I have founded user groups, hosted mailing lists, launched open
source projects, etc. I have contributed to major and minor projects all over
the damn place; I regularly get email thanking me for writing one of the best
known Perl manpages. I have spoken at conferences all over the world. I am
well known by certain segments of USENET, IRC, and mailing lists, and geeks
all over the world recognise my name when I travel; friends of mine threaten
to get tshirts printed saying &amp;ldquo;Yes, I know Skud&amp;rdquo; because of this. I have been
chewing people&amp;rsquo;s ears off about why open source/free software is awesome and
world-changing since I was 18 years old. And most of the above information is
readily available online. About half the first page of Google results (from
where I&amp;rsquo;m sitting right now) for &amp;ldquo;women in open source&amp;rdquo; mention me.&lt;/p&gt;

&lt;p&gt;Recently, I have also been documenting issues that women face in open source,
linking and discussing and synthesising and summarising and KEYNOTING OSCON.
(I started doing this a bit in 1998, but stepped back from it for a while, so
most of my women-in-open-source work is more recent.)&lt;/p&gt;

&lt;p&gt;And then I look at this thread and see that a) &amp;ldquo;women are just less passionate
about open source than men&amp;rdquo; and b) that nobody seems to believe us when we say
there is a problem.&lt;/p&gt;

&lt;p&gt;Fuck that. Follow some of those funny little blue underlined words and DO SOME
READING.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2&gt;Bruce Perens&lt;/h2&gt;

&lt;blockquote&gt;&lt;p&gt;OK, I&amp;rsquo;m going to guess that you might be Yuwei Lin, and that you are a woman.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2&gt;Skud&lt;/h2&gt;

&lt;blockquote&gt;&lt;p&gt;Bruce, I am Kirrily Robert, as a &lt;a href="http://lmgtfy.com/?q=skud"&gt;&lt;em&gt;trivial&lt;/em&gt; search&lt;/a&gt;
would have told you, if we hadn&amp;rsquo;t met in person on multiple occasions.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2&gt;Bruce Perens&lt;/h2&gt;

&lt;blockquote&gt;&lt;p&gt;Oh, sorry. I just went by who came up in the first half page of google
searches for
&lt;a href="http://lmgtfy.com/?q=women+in+Open+Source"&gt;women in Open Source&lt;/a&gt;. Lyn comes
up first here.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2&gt;tl;dr&lt;/h2&gt;

&lt;p&gt;Bruce Perens demonstrates one of the &amp;ldquo;established mechanisms which [are]
astonishingly effective at keeping [women] out&amp;rdquo; of the FOSS community. The irony
of his inability to recognize the existence of the mechanisms of which he is an
active part is lost on him and depresses the rest of us.&lt;/p&gt;

			&lt;p&gt;(This was posted at &lt;a href="http://codahale.com/foss-and-male-privilege/"&gt;codahale.com&lt;/a&gt;.)&lt;/p&gt;
		&lt;img src="http://feeds.feedburner.com/~r/codahale/~4/gjqUa5dav4k" height="1" width="1"/&gt;</content>
	<feedburner:origLink>http://codahale.com/foss-and-male-privilege/</feedburner:origLink></entry>
	
	<entry>
		<title>A Lesson In Timing Attacks (or, Don’t use MessageDigest.isEquals)</title>
		<link href="http://feedproxy.google.com/~r/codahale/~3/HxW3-pDTAcY/" />
		<updated>2009-08-13T00:00:00+02:00</updated>
		<id>http://codahale.com/a-lesson-in-timing-attacks</id>
		<content type="html">
			&lt;p&gt;&lt;a href="http://crypto.stanford.edu/~dabo/papers/ssl-timing.pdf"&gt;Timing attacks&lt;/a&gt;
are pretty horrible from the perspective of someone trying to write a secure
cryptosystem. They work against a programmer&amp;rsquo;s best instincts—don&amp;rsquo;t do extra
work—to give an attacker with access to a Statistics 101 textbook a good solid
grip on your application&amp;rsquo;s guts.&lt;/p&gt;

&lt;h2&gt;How the hell does that work?&lt;/h2&gt;

&lt;p&gt;In short, a timing attack uses statistical analysis of how long it takes your
application to do something in order to learn something about the data it&amp;rsquo;s
operating on. For &lt;a href="http://en.wikipedia.org/wiki/HMAC"&gt;HMACs&lt;/a&gt;, this means using
the amount of time your application takes to compare a given value with a
calculated value to learn information about the calculated value.&lt;/p&gt;

&lt;p&gt;Take &lt;a href="http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/"&gt;the recent Keyczar vulnerability that Nate Lawson found&lt;/a&gt;.
He was able to take the fact that Keyczar used a simple break-on-inequality
algorithm to compare a candidate HMAC digest with the calculated digest.&lt;/p&gt;

&lt;p&gt;This is the offending code in Python:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="python"&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;sig_bytes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;and in Java:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Arrays&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doFinal&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;sigBytes&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;A value which shares no bytes in common with the secret digest will return
immediately; a value which shares the first 15 bytes will return 15 compares
later. That&amp;rsquo;s a difference of perhaps microseconds, but given enough
attempts—which is usually easy to arrange in web applications (how many of you
throttle requests with bad session cookies?)—the random noise becomes a very
predictable, normally distributed skew, leaving only the signal.&lt;/p&gt;

&lt;h2&gt;Well that doesn&amp;rsquo;t seem that bad&lt;/h2&gt;

&lt;p&gt;Oh, but it is.&lt;/p&gt;

&lt;p&gt;I can choose what message I want to be authenticated—let&amp;rsquo;s say a session cookie
with a specific user ID—and then calculate 256 possible values:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;0000000000000000000000000000000000000000
0100000000000000000000000000000000000000
0200000000000000000000000000000000000000
... snip 250 ...
FD00000000000000000000000000000000000000
FE00000000000000000000000000000000000000
FF00000000000000000000000000000000000000
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I go through each of these values until I find one—
&lt;code&gt;A100000000000000000000000000000000000000&lt;/code&gt;—that takes a fraction of a
millisecond &lt;em&gt;longer&lt;/em&gt; than the others. I now know that the first byte of what the
HMAC for that message &lt;em&gt;should be&lt;/em&gt; is &lt;code&gt;A1&lt;/code&gt;. Repeat the process for the remaining
19 bytes, and all of a sudden I&amp;rsquo;m logged in as you.&lt;/p&gt;

&lt;h2&gt;You can&amp;rsquo;t possibly measure that, can you?&lt;/h2&gt;

&lt;p&gt;Right about now, most people are thinking about the improbability of measuring
the difference between two array comparisons in a web application, given all the
routers, parsers, servers, proxies, etc. in the way.&lt;/p&gt;

&lt;p&gt;According to Crosby et al.&amp;rsquo;s &lt;a href="http://www.cs.rice.edu/~dwallach/pub/crosby-timing2009.pdf"&gt;Opportunities And Limits Of Remote Timing Attacks&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;We have shown that, even though the Internet induces significant timing
jitter, we can reliably distinguish remote timing differences as low as 20µs.
A LAN environment has lower timing jitter, allowing us to reliably distinguish
remote timing differences as small as 100ns (possibly even smaller). These
precise timing differences can be distinguished with only hundreds or possibly
thousands of measurements.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;So. Almost microsecond resolution with hundreds to thousands of measurements.
Who wants to bet that network jitter compensation models get worse instead of
better?&lt;/p&gt;

&lt;p&gt;A worst-case scenario for guessing an HMAC would require 20 × 256 × &lt;code&gt;n&lt;/code&gt;
measurements, where &lt;code&gt;n&lt;/code&gt; is the number of measurements required to pin down a
single byte. So—around 5,000,000 requests. You could do that in less than a week
at a barely-perceptible 10 req/s.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s an attack which takes some planning and analysis, but it&amp;rsquo;s viable.&lt;/p&gt;

&lt;h2&gt;Well crap. Now what?&lt;/h2&gt;

&lt;p&gt;Instead of using a variable-time algorithm for comparing secrets, you should be
using constant-time algorithms. Lawson recommends something like the following
in Python:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="python"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;In Java, that would look like this:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isEqual&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;|=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Yay! Problem solved, right?&lt;/h2&gt;

&lt;p&gt;Oh, if only.&lt;/p&gt;

&lt;p&gt;Check out what&amp;rsquo;s inside of &lt;code&gt;java.security.MessageDigest&lt;/code&gt; as recently as Java
6.0 Update 15:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt;  * Compares two digests for equality. Does a simple byte compare.&lt;/span&gt;
&lt;span class="cm"&gt;  *&lt;/span&gt;
&lt;span class="cm"&gt;  * @param digesta one of the digests to compare.&lt;/span&gt;
&lt;span class="cm"&gt;  *&lt;/span&gt;
&lt;span class="cm"&gt;  * @param digestb the other digest to compare.&lt;/span&gt;
&lt;span class="cm"&gt;  *&lt;/span&gt;
&lt;span class="cm"&gt;  * @return true if the digests are equal, false otherwise.&lt;/span&gt;
&lt;span class="cm"&gt;  */&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt; &lt;span class="nf"&gt;isEqual&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt; &lt;span class="n"&gt;digesta&lt;/span&gt;&lt;span class="o"&gt;[],&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt; &lt;span class="n"&gt;digestb&lt;/span&gt;&lt;span class="o"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digesta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;digestb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;digesta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digesta&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;digestb&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Wait What&lt;/h2&gt;

&lt;p&gt;Yep. Byte-by-byte comparison; returns on first inequality. Just what we don&amp;rsquo;t
need.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ll be blunt here: &lt;strong&gt;any Java application which compares client-provided data
to a secret value using &lt;code&gt;MessageDigest.isEqual&lt;/code&gt; is vulnerable to timing
attacks&lt;/strong&gt;. This includes HMACs, decryption results, etc.&lt;/p&gt;

&lt;p&gt;I reported this to Sun on July 22nd, 2009. It&amp;rsquo;s
&lt;a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6863503"&gt;Bug # 6863503&lt;/a&gt;,
which isn&amp;rsquo;t publicly viewable due to the security concerns. Besides the
automated email with the ticket number, I haven&amp;rsquo;t heard anything from Sun since
then. In my bug report, I was explicit about my intent to follow through
according to the &lt;a href="http://www.wiretrip.net/rfp/policy.html"&gt;RFPolicy&lt;/a&gt;, which says&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;D. If the MAINTAINER goes beyond 5 working days without any communication to
the ORIGINATOR, the ORIGINATOR may choose to disclose the ISSUE. The
MAINTAINER is responsible for providing regular status updates (regarding the
resolution of the ISSUE) at least once every 5 working days.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;So here I am, fully disclosing a rather large cryptographic vulnerability in one
of the largest programming platforms there is. I can&amp;rsquo;t tell if that&amp;rsquo;s terrible
or awesome.&lt;/p&gt;

&lt;h2&gt;tl;dr&lt;/h2&gt;

&lt;p&gt;Replace your usage of &lt;code&gt;MessageDigest.isEqual&lt;/code&gt; with a constant-time algorithm,
like the one above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every time you compare two values, ask yourself: what could someone do if
they knew either of these values?&lt;/strong&gt; If the answer is at all meaningful, use a
constant-time algorithm to compare them.&lt;/p&gt;

&lt;h2&gt;A Side Note&lt;/h2&gt;

&lt;p&gt;This would be substantially less of an issue if more cryptographic libraries had
better encapsulation. An HMAC is &lt;em&gt;not&lt;/em&gt; just a series of characters or bytes—why
treat it as such? Why have such a crucial piece of cryptography squirt out its
state for others to man-handle?&lt;/p&gt;

&lt;h2&gt;Thanks&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://www.root.org/~nate/"&gt;Nate Lawson&lt;/a&gt;&amp;rsquo;s Keyczar find got me thinking about
timing attacks in my own code. His
&lt;a href="http://www.youtube.com/watch?v=ySQl0NhW1J0"&gt;When Crypto Attacks&lt;/a&gt; talk should be
required watching for everyone with access to a compiler.&lt;/p&gt;

&lt;h2&gt;Updated August 13, 2009&lt;/h2&gt;

&lt;p&gt;As &lt;a href="http://news.ycombinator.com/item?id=761059"&gt;sophacles on Hacker News&lt;/a&gt;
pointed out, I had overly refactored the suggested constant-time algorithms and
introduced a more subtle timing attack vulnerability via the return
statement&amp;rsquo;s boolean expression short-circuit. The algorithm has been updated to
fix this.&lt;/p&gt;

&lt;h2&gt;Updated December 3, 2009&lt;/h2&gt;

&lt;p&gt;The timing attack vulnerability in &lt;code&gt;MessageDigest&lt;/code&gt; was fixed in
&lt;a href="http://java.sun.com/javase/6/webnotes/6u17.html"&gt;Java SE 6 Update 17&lt;/a&gt;.&lt;/p&gt;

			&lt;p&gt;(This was posted at &lt;a href="http://codahale.com/a-lesson-in-timing-attacks/"&gt;codahale.com&lt;/a&gt;.)&lt;/p&gt;
		&lt;img src="http://feeds.feedburner.com/~r/codahale/~4/HxW3-pDTAcY" height="1" width="1"/&gt;</content>
	<feedburner:origLink>http://codahale.com/a-lesson-in-timing-attacks/</feedburner:origLink></entry>
	
	<entry>
		<title>How Not To Fix A Security Bug</title>
		<link href="http://feedproxy.google.com/~r/codahale/~3/iiOVKX2Op54/" />
		<updated>2009-06-14T00:00:00+02:00</updated>
		<id>http://codahale.com/how-not-to-fix-a-security-bug</id>
		<content type="html">
			&lt;h2&gt;November 25th, 2008&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Tadayoshi Funaba opens &lt;a href="http://redmine.ruby-lang.org/issues/show/794"&gt;Bug #794&lt;/a&gt;
in the Ruby Issue Tracking System describing a segmentation fault when huge
decimal strings are converted into &lt;code&gt;BigDecimal&lt;/code&gt; instances.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;November 26th, 2008&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Matz closes Bug #794 with &lt;a href="http://redmine.ruby-lang.org/repositories/revision/ruby-19?rev=20359"&gt;r20359&lt;/a&gt;
to Ruby 1.9&amp;rsquo;s trunk.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;November 27th, 2008 to June 2nd, 2009&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Every site running Ruby 1.8.x which creates BigDecimal instances from
client-provided data is vulnerable to a Denial-of-Service attack which Ruby
Core developers have already fixed but not backported.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;June 3rd, 2009&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2009-1904"&gt;CVE-2009-1904&lt;/a&gt;
is assigned.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;June 7th, 2009&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;ruby-core notifies the &lt;a href="http://en.wikipedia.org/wiki/Vendor-sec"&gt;vendor-sec&lt;/a&gt;
mailing list of the vulnerability.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;June 8th, 2009&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://bugs.gentoo.org/show_bug.cgi?id=273213"&gt;Bug 273213&lt;/a&gt; is created in
the Gentoo bug tracker to address CVE-2009-1904. Like most tickets for
as-yet-undisclosed security vulnerabilities, the ticket was marked
confidential and that &amp;ldquo;no information should be disclosed until [the
vulnerability] is made public.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Michael Koziarski creates a private GitHub project, &lt;a href="http://github.com/NZKoz/bigdecimal-segfault-fix/tree/master"&gt;bigdecimal-segfault-fix&lt;/a&gt;
with a workaround for the bug.&lt;/li&gt;
&lt;li&gt;Kirk Haines &lt;a href="http://github.com/rubyspec/rubyspec/commit/95c0abbe07bf350f83d2454eb080b0bd315d59d4"&gt;commits a change&lt;/a&gt;
to the RubySpec project which adds a test to ensure Ruby implementations
don&amp;rsquo;t &amp;ldquo;segfault when using a very large string to build [a BigDecimal].&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;June 9th, 2009&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The vulnerability &lt;a href="http://www.ruby-lang.org/en/news/2009/06/09/dos-vulnerability-in-bigdecimal/"&gt;is announced&lt;/a&gt; as well as the release of Ruby 1.8.7-p173.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.vuxml.org/freebsd/62e0fbe5-5798-11de-bb78-001cc0377035.html"&gt;A ticket is added&lt;/a&gt;
to FreeBSD&amp;rsquo;s security bug tracker to address CVE-2009-1904.&lt;/li&gt;
&lt;li&gt;Michael Koziarski &lt;a href="http://groups.google.com/group/rubyonrails-security/msg/fad60751e2b9b4f6?"&gt;announces the vulnerability&lt;/a&gt;
to the rails-security mailing list.&lt;/li&gt;
&lt;li&gt;Kirk Haines &lt;a href="http://redmine.ruby-lang.org/issues/show/1589"&gt;adds Backport #1589&lt;/a&gt;
to the Ruby Issue Tracking System describing a patch which &amp;ldquo;eliminate[s] some
BigDecimal bugs.&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Kirk Haines &lt;a href="http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/3106062ee1df078a/0625d1bd36da13db?lnk=raot&amp;amp;fwc=2"&gt;announces the release of Ruby 1.8.6-p369&lt;/a&gt;, which includes a fix for CVE-2009-1904.&lt;/li&gt;
&lt;li&gt;Michael Koziarski makes the bigdecimal-segfault-fix project public on GitHub.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;June 10th, 2009&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Barry Hess finds a bug introduced in 1.8.7-p173 &lt;a href="http://www.getharvest.com/blog/2009/06/ruby-denial-of-service-patch-breaks-bigdecimal-to_f-method/"&gt;breaks BigDecimal#to_f&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bugzilla.redhat.com/show_bug.cgi?id=504958"&gt;A ticket is added&lt;/a&gt; to
the Red Hat bug tracker to address CVE-2009-1904.&lt;/li&gt;
&lt;li&gt;The vulnerability &lt;a href="http://weblog.rubyonrails.org/2009/6/10/dos-vulnerability-in-ruby/"&gt;is announced&lt;/a&gt;
on the Ruby On Rails blog.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bugs.launchpad.net/ubuntu/+source/ruby1.8/+bug/385436"&gt;A ticket is added&lt;/a&gt; to
the Ubuntu bug tracker to address CVE-2009-1904.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=532689"&gt;A ticket is added&lt;/a&gt;
to the Debian bug tracker to address CVE-2009-1904.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;June 12th, 2009&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.freshports.org/commit.php?category=lang&amp;amp;port=ruby18&amp;amp;files=yes&amp;amp;message_id=200906122244.n5CMiug0080745@repoman.freebsd.org"&gt;A fix is released&lt;/a&gt; for FreeBSD.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;June 13th, 2009&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=532689#20"&gt;A fix is released&lt;/a&gt; for Debian Unstable. This fix contains the bug that Barry Hess found.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;June 14th, 2009&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No fix has been released for Ubuntu.&lt;/li&gt;
&lt;li&gt;No fix has been released for Red Hat.&lt;/li&gt;
&lt;li&gt;No fix has been released for Fedora Core.&lt;/li&gt;
&lt;li&gt;No fix has been released for Gentoo.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;June 15th, 2009&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ruby 1.8.7-p174 &lt;a href="http://www.ruby-forum.com/topic/189053#827091"&gt;is released&lt;/a&gt;
without the &lt;code&gt;BigDecimal#to_f&lt;/code&gt; bug.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;tl;dr&lt;/h2&gt;

&lt;p&gt;This is not a coordinated disclosure. This is a clusterfuck. If you are
responsible for running a secure MRI/Ruby installation, your only hope is to pay
attention to all changes made to Ruby&amp;rsquo;s trunk and backport any fixes yourself.
Depending on your operating system vendor is not a viable strategy, as
downstream vendors are not given sufficient advance warning and are presented
with fixes which introduce other bugs or do not apply cleanly to the last
released version.&lt;/p&gt;

&lt;h2&gt;Updated June 16th, 2009&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.koziarski.net/"&gt;Michael Koziarski&lt;/a&gt; dropped me a note to clarify a
few things. First, his GitHub project was private and was only opened to the
public &lt;em&gt;after&lt;/em&gt; the vulnerability was announced. Second, ruby-core sent an
email to the &lt;a href="http://en.wikipedia.org/wiki/Vendor-sec"&gt;vendor-sec&lt;/a&gt; mailing
list 48 hours before the disclosure. I&amp;rsquo;ve updated the timeline to reflect
these changes.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/jdludlow"&gt;James Ludlow&lt;/a&gt; &lt;a href="http://twitter.com/jdludlow/status/2166873415"&gt;let me know about&lt;/a&gt;
a bug introduced in 1.8.7-p173 and fixed in 1.8.7-p174.&lt;/li&gt;
&lt;li&gt;Updated my conclusions based on the new information. Still not happy, but more
accurate in what I&amp;rsquo;m unhappy about.&lt;/li&gt;
&lt;/ul&gt;


			&lt;p&gt;(This was posted at &lt;a href="http://codahale.com/how-not-to-fix-a-security-bug/"&gt;codahale.com&lt;/a&gt;.)&lt;/p&gt;
		&lt;img src="http://feeds.feedburner.com/~r/codahale/~4/iiOVKX2Op54" height="1" width="1"/&gt;</content>
	<feedburner:origLink>http://codahale.com/how-not-to-fix-a-security-bug/</feedburner:origLink></entry>
	
	<entry>
		<title>What Makes Jersey Interesting: Injection Providers</title>
		<link href="http://feedproxy.google.com/~r/codahale/~3/JVFLr_UjNO0/" />
		<updated>2009-05-16T00:00:00+02:00</updated>
		<id>http://codahale.com/what-makes-jersey-interesting-injection-providers</id>
		<content type="html">
			&lt;p&gt;&lt;em&gt;Ok, let&amp;rsquo;s get back to the geeky stuff.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Another interesting thing about Jersey (in addition to
&lt;a href="http://codahale.com/what-makes-jersey-interesting-parameter-classes"&gt;parameter classes&lt;/a&gt;)
is the way it uses dependency injection.&lt;/p&gt;

&lt;p&gt;Jersey doesn&amp;rsquo;t have an abstract base class for resources, like Rails'
&lt;code&gt;ActionController::Base&lt;/code&gt; or Restlet&amp;rsquo;s &lt;code&gt;Resource&lt;/code&gt;. This removes the obvious way
of retrieving information about the incoming request: from the base class.&lt;/p&gt;

&lt;p&gt;Take this Rails controller action, for example:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="ruby"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;
  &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:text&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;You asked for &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;request&lt;/code&gt; is a method defined on &lt;code&gt;ActionController::Base&lt;/code&gt; which returns an
object encapsulating the information about the current HTTP request.&lt;/p&gt;

&lt;p&gt;But how would you test this action in isolation? Hopefully the base class
provides an easy way of passing in a mock request object, or else you&amp;rsquo;re stuck
modifying instance variables or partially mocking the class you&amp;rsquo;re trying to
test.&lt;/p&gt;

&lt;h2&gt;So what&amp;rsquo;s a better way of doing that?&lt;/h2&gt;

&lt;p&gt;Jersey avoids this situation by injecting the required information into the
resource class:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Context&lt;/span&gt; &lt;span class="n"&gt;UriInfo&lt;/span&gt; &lt;span class="n"&gt;uriInfo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;You asked for &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;uriInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAbsolutePath&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Jersey detects the &lt;code&gt;@Context&lt;/code&gt; annotation and automatically injects a &lt;code&gt;UriInfo&lt;/code&gt;
with the current request&amp;rsquo;s data into the method. You can do this for
&lt;code&gt;HttpHeaders&lt;/code&gt;, &lt;code&gt;SecurityContext&lt;/code&gt;, and a few other Jersey classes.&lt;/p&gt;

&lt;p&gt;When it comes time to test this class, it&amp;rsquo;s a simple matter of making a mock
&lt;code&gt;UriInfo&lt;/code&gt; and passing it in:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;itReturnsTheRequestURI&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;MyResource&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MyResource&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;UriInfo&lt;/span&gt; &lt;span class="n"&gt;uriInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UriInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;when&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uriInfo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAbsolutePath&lt;/span&gt;&lt;span class="o"&gt;()).&lt;/span&gt;&lt;span class="na"&gt;thenReturn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/wooooo&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    
    &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;show&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uriInfo&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;You asked for /wooooo&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Because the resource class doesn&amp;rsquo;t go out and get the &lt;code&gt;UriInfo&lt;/code&gt; itself, it&amp;rsquo;s
much easier to test.&lt;/p&gt;

&lt;p&gt;What takes this feature from Neat to Indispensable is the fact that Jersey opens
this infrastructure to you: it&amp;rsquo;s easy to write your own injection providers to
peel arbitrary bits of an HTTP request off and inject them into your resources.&lt;/p&gt;

&lt;h2&gt;1.. 2.. 3.. Example time!&lt;/h2&gt;

&lt;p&gt;As an easy example, let&amp;rsquo;s take the request&amp;rsquo;s locale, as determined by its
&lt;code&gt;Accept-Language&lt;/code&gt; header. Out of the box, Jersey gives us access to this via
&lt;code&gt;HttpHeaders#getAcceptableLanguages()&lt;/code&gt;, which returns a list of &lt;code&gt;Locale&lt;/code&gt;
instances in order of preference.&lt;/p&gt;

&lt;p&gt;But it&amp;rsquo;s a tedious thing to have our resource class have an &lt;code&gt;HttpHeaders&lt;/code&gt;
instance injected and then get the first item from the
&lt;code&gt;getAcceptableLanguages()&lt;/code&gt; results:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;uppercase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Context&lt;/span&gt; &lt;span class="n"&gt;HttpHeaders&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;this is lowercase&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toUppercase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAcceptableLanguages&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;In order to test that, we&amp;rsquo;ll have to come up with an &lt;code&gt;HttpHeaders&lt;/code&gt; mock and stub
its &lt;code&gt;getAcceptableLanguages()&lt;/code&gt; to return a list of locales. Bleagh.&lt;/p&gt;

&lt;p&gt;&lt;ins&gt;
&lt;strong&gt;Update:&lt;/strong&gt; If you&amp;rsquo;re wondering why you&amp;rsquo;d need a &lt;code&gt;Locale&lt;/code&gt; to convert a string to
uppercase, check out the Turkish language. The uppercase version of &lt;strong&gt;i&lt;/strong&gt;
(U+0069) is &lt;strong&gt;İ&lt;/strong&gt; (U+0130), and the lowercase version of &lt;strong&gt;I&lt;/strong&gt; (U+0049) is &lt;strong&gt;ı&lt;/strong&gt;
(U+0131). It matters.
&lt;/ins&gt;&lt;/p&gt;

&lt;h2&gt;Now make it uglier&lt;/h2&gt;

&lt;p&gt;In keeping with my &amp;ldquo;so what if it looks good on a slide&amp;rdquo; motif here, I&amp;rsquo;m also
going to throw in error handling: what if the user doesn&amp;rsquo;t specify a locale?&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;uppercase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Context&lt;/span&gt; &lt;span class="n"&gt;HttpHeaders&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Locale&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;locales&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getAcceptableLanguages&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Locale&lt;/span&gt; &lt;span class="n"&gt;selectedLocale&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;selectedLocale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Locale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;US&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;selectedLocale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;locales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;this is lowercase&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toUppercase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;selectedLocale&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That&amp;rsquo;s goddamn horrible&amp;mdash;we&amp;rsquo;ll have to test that logic all over the place,
lest we end up throwing an &lt;code&gt;IndexOutOfBoundsException&lt;/code&gt; because someone&amp;rsquo;s HTTP
client has funny ideas about valid locales are.&lt;/p&gt;

&lt;p&gt;It would be nice to have the locale-selecting code in its own class, and to do
that in the same way that our &lt;code&gt;HttpHeaders&lt;/code&gt; instance was injected.&lt;/p&gt;

&lt;h2&gt;I assume you have some kind of plan&lt;/h2&gt;

&lt;p&gt;In order to do that we&amp;rsquo;ll need to write two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A class implementing &lt;code&gt;Injectable&amp;lt;Locale&amp;gt;&lt;/code&gt;, which will be responsible for
extracting a &lt;code&gt;Locale&lt;/code&gt; from an HTTP request context.&lt;/li&gt;
&lt;li&gt;A class implementing &lt;code&gt;InjectableProvider&amp;lt;Locale&amp;gt;&lt;/code&gt;, which will be responsible
for injecting instances of #1.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Jersey has a specific class to handle the first responsibility:
&lt;code&gt;AbstractHttpContextInjectable&lt;/code&gt; which is used to inject information from the
HTTP context into resource classes. The second responsibility is simple enough
to not require a template base class.&lt;/p&gt;

&lt;h2&gt;Ok, let&amp;rsquo;s do it&lt;/h2&gt;

&lt;p&gt;Luckily for us, we can kill two birds with one stone and implement both
complimentary responsibilities in a single class:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Provider&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LocaleProvider&lt;/span&gt;
      &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AbstractHttpContextInjectable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Locale&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;InjectableProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Injectable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getInjectable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ComponentContext&lt;/span&gt; &lt;span class="n"&gt;ic&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Locale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ComponentScope&lt;/span&gt; &lt;span class="nf"&gt;getScope&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ComponentScope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PerRequest&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    
    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Locale&lt;/span&gt; &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Locales&lt;/span&gt; &lt;span class="n"&gt;locales&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRequest&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getAcceptableLanguages&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Locale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;US&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;locales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This is kind of a complicated class. Let&amp;rsquo;s cover a few things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;@Provider&lt;/code&gt; annotation marks it so that Jersey will add it as an injection
provider.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;getInjectable&lt;/code&gt; method checks to see that &lt;code&gt;c&lt;/code&gt; is &lt;code&gt;Locale&lt;/code&gt;&amp;mdash;that is, if
  Jersey is asking this provider if it can  inject a &lt;code&gt;Locale&lt;/code&gt;. If so, it
  returns itself to do the injection.  Otherwise, it returns &lt;code&gt;null&lt;/code&gt; to
  indicate there&amp;rsquo;s nothing it can inject.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;getScope&lt;/code&gt; method indicates that the returned injectable is only
meaningful on a per-request basis.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;getValue&lt;/code&gt; method is where the real logic happens. Once the
&lt;code&gt;LocaleProvider&lt;/code&gt; instance has been returned from &lt;code&gt;getInjectable&lt;/code&gt;, Jersey
passes it an &lt;code&gt;HttpContext&lt;/code&gt;, which contains all the relevant information about
the HTTP  request. It returns the most-preferred locale, including error
handling.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;When we put &lt;code&gt;LocaleProvider&lt;/code&gt; in a package that Jersey&amp;rsquo;s configured to scan, we
can reduce our resource class logic to this:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;uppercase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@Context&lt;/span&gt; &lt;span class="n"&gt;Locale&lt;/span&gt; &lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;this is lowercase&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toUppercase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Then our test looks like this:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;itReturnsAnUppercaseString&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;MyResource&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MyResource&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    
    &lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;uppercase&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Locale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CANADA&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;THIS IS LOWERCASE&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;But I don&amp;rsquo;t think we&amp;rsquo;re done yet.&lt;/p&gt;

&lt;h2&gt;How many times you wanna write this thing&lt;/h2&gt;

&lt;p&gt;Much like &lt;a href="/what-makes-jersey-interesting-parameter-classes"&gt;parameter classes&lt;/a&gt;,
our code gets cleaner the more injection providers we write, so we need to
extract out the guts into a base class:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AbstractInjectableProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AbstractHttpContextInjectable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="n"&gt;InjectableProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;AbstractInjectableProvider&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Injectable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getInjectable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ComponentContext&lt;/span&gt; &lt;span class="n"&gt;ic&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getInjectable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ic&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Injectable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;getInjectable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ComponentContext&lt;/span&gt; &lt;span class="n"&gt;ic&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ComponentScope&lt;/span&gt; &lt;span class="nf"&gt;getScope&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ComponentScope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PerRequest&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now our provider is sleek and shiny:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Provider&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LocaleProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AbstractInjectableProvider&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Locale&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;LocaleProvider&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Locale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Locale&lt;/span&gt; &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpContext&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;Locales&lt;/span&gt; &lt;span class="n"&gt;locales&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRequest&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getAcceptableLanguages&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isEmpty&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Locale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;US&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;locales&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now both our resource class and our &lt;code&gt;LocaleProvider&lt;/code&gt; are composed and testable.&lt;/p&gt;

&lt;p&gt;I love it when a plan comes together.&lt;/p&gt;

&lt;h2&gt;tl;dr&lt;/h2&gt;

&lt;p&gt;Jersey has an internal dependency injection system which allows you to write
small, focused classes to extract aspects of an HTTP request&amp;mdash;in our case, the
request&amp;rsquo;s locale&amp;mdash;and inject them into your resource classes as an object of
an appropriate type. This makes for smaller, more composed, more testable
resource classes, which in turn makes for an application which is easier to
change.&lt;/p&gt;

			&lt;p&gt;(This was posted at &lt;a href="http://codahale.com/what-makes-jersey-interesting-injection-providers/"&gt;codahale.com&lt;/a&gt;.)&lt;/p&gt;
		&lt;img src="http://feeds.feedburner.com/~r/codahale/~4/JVFLr_UjNO0" height="1" width="1"/&gt;</content>
	<feedburner:origLink>http://codahale.com/what-makes-jersey-interesting-injection-providers/</feedburner:origLink></entry>
	
	<entry>
		<title>Ruby and Male Privilege</title>
		<link href="http://feedproxy.google.com/~r/codahale/~3/K7JJk9BUWio/" />
		<updated>2009-05-10T00:00:00+02:00</updated>
		<id>http://codahale.com/ruby-and-male-privilege</id>
		<content type="html">
			&lt;h2&gt;Act One&lt;/h2&gt;

&lt;p&gt;I read this today:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;A female computer science professor wrote:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;[A]t a conference in France, a male speaker (French), who was speaking about
the importance of testing, showed an overhead slide of a naked woman with a
caption of the sort&amp;mdash;&amp;lsquo;Would you buy this product without testing it
first?&amp;rsquo; There were only 2 or 3 women in the audience (of about 150), but I
had fleeting feelings of having accidentally walked into a stag party and
wondering if he had either not expected any women to be there or had
discounted the importance of directing his remarks to the women in the
audience.&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;

&lt;p&gt;&amp;mdash;Ellen Spertus, &lt;em&gt;&lt;a href="http://people.mills.edu/spertus/Gender/pap/pap.html"&gt;Why are There so Few Female Computer Scientists?&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dr. Spertus wrote that paper in 1991.&lt;/p&gt;

&lt;p&gt;In 1991, I used a gift certificate I won in a junior high car-washing fundraiser
content to purchase a tape of Pearl Jam&amp;rsquo;s &lt;em&gt;Ten&lt;/em&gt; from the local record store.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pearl Jam.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Junior High.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A tape.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;Act Two&lt;/h2&gt;

&lt;p&gt;On April 18th, 2009, Matt Aimonetti gave a presentation on CouchDB entitled
&lt;em&gt;CouchDB: Perform Like A Pr0n Star&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src="/images/couch-db.png" title="The first slide from Matt Aimonetti's presentation" alt="The first slide from Matt Aimonetti's presentation, featuring a woman's rear in lingerie." /&gt;&lt;/p&gt;

&lt;p&gt;You can &lt;a href="http://www.slideshare.net/mattetti/couchdb-perform-like-a-pr0n-star"&gt;see the rest of the slides here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Intermission&lt;/h2&gt;

&lt;p&gt;In the &lt;strong&gt;eighteen&lt;/strong&gt; intervening years, what&amp;rsquo;s changed?&lt;/p&gt;

&lt;p&gt;Let me rephrase: &lt;strong&gt;in the lifetime of this year&amp;rsquo;s college freshman&lt;/strong&gt;, what&amp;rsquo;s
changed?&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s a depressing question.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s another one: when she graduates in 2013, what will have changed for that
freshman?&lt;/p&gt;

&lt;h2&gt;Act Three&lt;/h2&gt;

&lt;p&gt;A few days ago, I noticed this exchange on Twitter:&lt;/p&gt;

&lt;p&gt;&lt;img src="/images/staying-classy.png" title="An online exchange after the dust had cleared." alt="blah" /&gt;&lt;/p&gt;

&lt;p&gt;And &lt;a href="http://twitter.com/dhh/status/1631342976"&gt;this gem&lt;/a&gt; from David Heinemeier
Hansson, creator of Rails:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;I do think the spheres of the female body gives life wonder. Suppressing all
our animal instincts is futile.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Ladies and gentlemen, the leading lights of the Ruby community.&lt;/p&gt;

&lt;h2&gt;tl;dr&lt;/h2&gt;

&lt;p&gt;Read &lt;a href="http://people.mills.edu/spertus/Gender/pap/pap.html"&gt;Why Are There So Few Female Computer Scientists&lt;/a&gt; and
&lt;a href="http://www.tldp.org/HOWTO/Encourage-Women-Linux-HOWTO/"&gt;HOWTO Encourage Women In Linux&lt;/a&gt;. And honestly,
I&amp;rsquo;m beginning to wonder if the women who aren&amp;rsquo;t joining the Ruby community
aren&amp;rsquo;t making the right choice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Also be sure to read
&lt;a href="http://lafalafu.com/krc/privilege.html"&gt;The Male Programmer Privilege Checklist&lt;/a&gt;
for examples of the subtle privileges that male programmers enjoy, almost always
without knowing it.&lt;/p&gt;

			&lt;p&gt;(This was posted at &lt;a href="http://codahale.com/ruby-and-male-privilege/"&gt;codahale.com&lt;/a&gt;.)&lt;/p&gt;
		&lt;img src="http://feeds.feedburner.com/~r/codahale/~4/K7JJk9BUWio" height="1" width="1"/&gt;</content>
	<feedburner:origLink>http://codahale.com/ruby-and-male-privilege/</feedburner:origLink></entry>
	
	<entry>
		<title>When Formality Works</title>
		<link href="http://feedproxy.google.com/~r/codahale/~3/Wnp8aBuGXeA/" />
		<updated>2009-05-07T00:00:00+02:00</updated>
		<id>http://codahale.com/when-formality-works</id>
		<content type="html">
			&lt;p&gt;&lt;a href="http://yehudakatz.com/2009/05/02/incentivizing-innovation/"&gt;On his blog, Yehuda Katz writes&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;One of the things I love the most about the Ruby community is how easy it is
to try out small mutations in practices, which leads to very rapid evolution
in best practices. Rather than having the community look toward authority to
design, plan, and implement &amp;ldquo;best practices&amp;rdquo; (a la the JSR model), members of
the Ruby community try different things, and have rapidly made refinements to
the practices over time.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;In general, I agree with Yehuda about &lt;a href="http://obiefernandez.com"&gt;Obie&lt;/a&gt;&amp;rsquo;s
&lt;a href="http://railsmaturitymodel.com/"&gt;current advertising campaign&lt;/a&gt;: playing
hot-or-not with the bullet points in a HashRocket sales brochure does not make
for a compelling discussion of what makes good software, nor does it actually
help the community. (But then, I don&amp;rsquo;t think helping the community is the
intent behind RMM&amp;mdash;I think it&amp;rsquo;s about drumming up business by being
thoughtleaders.)&lt;/p&gt;

&lt;p&gt;But I have an important nit to pick.&lt;/p&gt;

&lt;h2&gt;That&amp;rsquo;s not how the JSR model works.&lt;/h2&gt;

&lt;p&gt;Java programmers don&amp;rsquo;t sit around feeling helpless waiting for &lt;em&gt;JSR-9918: Doing
That Thing You Get Paid To Do&lt;/em&gt; to be finalized. Instead, they haul off and
implement &lt;a href="http://functionaljava.org/"&gt;crazy experiments&lt;/a&gt; and
&lt;a href="http://www.thimbleware.com/projects/jrel"&gt;solve their problems&lt;/a&gt; in new and
unique ways &lt;em&gt;just like every other programming community&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="http://jcp.org/en/procedures/jcp2"&gt;Java Community Process&lt;/a&gt;, you write
a JSR proposal describing what you&amp;rsquo;d like to standardize and why. &lt;a href="http://www.jcp.org/en/jsr/detail?id=311#orig"&gt;Here&amp;rsquo;s the original proposal for JSR-311, about RESTful web services for Java&lt;/a&gt;.
Then you assemble an expert group&amp;mdash;a group of people who are both
knowledgeable and interested in the subject&amp;mdash;and write a bunch of drafts, go
through a bunch of reviews, and finally end up with both a free reference
implementation of the standard and a test suite to verify API compliance with
the standard.&lt;/p&gt;

&lt;p&gt;Horrible, I know.&lt;/p&gt;

&lt;p&gt;It is incredibly bureaucratic, yes. But it&amp;rsquo;s a standardization process. It&amp;rsquo;s not
where innovation starts, it&amp;rsquo;s where it ends. And that&amp;rsquo;s as it should be.&lt;/p&gt;

&lt;p&gt;The whole point of a standard is to describe a fixed set of practices that
people can take for granted. Once they can take it for granted, they can begin
to focus on other things.&lt;/p&gt;

&lt;h2&gt;For example, Rack.&lt;/h2&gt;

&lt;p&gt;One of the more exciting things to have happened in the Ruby web development
community is &lt;a href="http://rack.rubyforge.org/"&gt;Rack&lt;/a&gt;. It&amp;rsquo;s not a very sexy
project&amp;mdash;one can&amp;rsquo;t claim to be a web framework middleware ninja&amp;mdash;but it has an
incredible amount of utility: it&amp;rsquo;s standardized the interface between web
application containers&amp;mdash;&lt;a href="http://mongrel.rubyforge.org/"&gt;Mongrel&lt;/a&gt;,
&lt;a href="http://code.macournoyer.com/thin/"&gt;Thin&lt;/a&gt;,
&lt;a href="http://ebb.rubyforge.org/"&gt;Ebb&lt;/a&gt;,
&lt;a href="http://www.modrails.com/"&gt;Passenger&lt;/a&gt;,
&lt;a href="http://kenai.com/projects/jruby-rack/pages/Home"&gt;Glassfish, Jetty, Tomcat, JBoss, SpringSource, Google App Engine&lt;/a&gt;,
&lt;a href="http://github.com/chneukirchen/rack/blob/d221938a6401d956ac6cfdc892f9b1c11b1fa31a/lib/rack/handler/webrick.rb"&gt;WEBrick&lt;/a&gt;,
&lt;a href="http://litespeedtech.com/"&gt;LiteSpeed&lt;/a&gt;,
&lt;a href="http://github.com/KirinDave/fuzed/tree/master"&gt;Fuzed&lt;/a&gt;,
&lt;a href="http://github.com/chneukirchen/rack/blob/d221938a6401d956ac6cfdc892f9b1c11b1fa31a/lib/rack/handler/cgi.rb"&gt;CGI&lt;/a&gt;,
&lt;a href="http://github.com/chneukirchen/rack/blob/d221938a6401d956ac6cfdc892f9b1c11b1fa31a/lib/rack/handler/fastcgi.rb"&gt;FastCGI&lt;/a&gt;,
&lt;a href="http://github.com/chneukirchen/rack/blob/d221938a6401d956ac6cfdc892f9b1c11b1fa31a/lib/rack/handler/scgi.rb"&gt;SCGI&lt;/a&gt;,
&lt;a href="http://swiftiply.swiftcore.org/mongrel.html"&gt;EventedMongrel, SwiftipliedMongrel&lt;/a&gt;&amp;mdash;and Ruby web applications.&lt;/p&gt;

&lt;p&gt;Thanks to Rack&amp;rsquo;s acceptance, you write a web application to work with a minimal
interface and deploy it on a wide variety of infrastructure without needing to
write your own adapter code. You no longer need to care about the glue code
between your web server and your web application. You can then spend time doing
other things, &lt;em&gt;like caring about your actual web application.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;Why did Rack succeed?&lt;/h2&gt;

&lt;p&gt;Rack succeeded because it has a &lt;a href="http://rack.rubyforge.org/doc/SPEC.html"&gt;spec&lt;/a&gt;,
a &lt;a href="http://github.com/rack/rack/tree/master"&gt;reference implementation&lt;/a&gt; and even
a &lt;a href="http://github.com/rack/rack/blob/815342a8e15db564b766f209ffb1e340233f064f/lib/rack/lint.rb"&gt;test suite&lt;/a&gt;
to ensure spec compatibility.&lt;/p&gt;

&lt;p&gt;It doesn&amp;rsquo;t matter if Christian Neukirchen&amp;mdash;not that he would&amp;mdash;hauls off and
destroys Rack as a library; the spec still exists, and implementations of it can
be written again and again.&lt;/p&gt;

&lt;p&gt;But a spec is not sufficient, obviously. You can&amp;rsquo;t just crack open Word and
start writing fiction in order to make your project gain traction. You need to
extract from existing projects a common pattern, round off rough edges, and
resolve long-standing issues. Rack did that. It took the various Rails dispatch
glue code and other half-assed Ruby middleware implementations, looked at what
worked for the &lt;a href="http://www.python.org/dev/peps/pep-0333"&gt;Python community&lt;/a&gt;, came
up with some iterations, got an &lt;em&gt;astounding&lt;/em&gt; amount of feedback from concerned,
knowledgeable people in the Ruby community, and ended up producing something
which has seen widespread adoption in a short period of time.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m not sure why Yehuda feels compelled to bring out the scare quotes when
referring to these as &amp;ldquo;best practices.&amp;rdquo; It&amp;rsquo;s a good process and it obviously
works.&lt;/p&gt;

&lt;h2&gt;Ruby needs more of this.&lt;/h2&gt;

&lt;p&gt;The Ruby community has not had a great history of doing this.
&lt;a href="http://rcrchive.net/"&gt;Ruby Change Requests&lt;/a&gt;, a mechanism for proposed changes
to the Ruby language, were mothballed because ruby-core simply didn&amp;rsquo;t want to
deal with it. It&amp;rsquo;s much easier just making changes and having everyone else run
around fixing the ways in which the latest patch release of Ruby totally breaks
their code. It was discontent with this process which produced the
&lt;a href="http://www.rubyspec.org"&gt;RubySpec project&lt;/a&gt; which, say, &lt;em&gt;looked toward authority
to design, plan, and implement &amp;ldquo;best practices&amp;rdquo;&lt;/em&gt; regarding the Ruby language.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Because trying to build a business on top of a Ruby interpreter in which
ruby-core is constantly trying out &amp;ldquo;small mutations&amp;rdquo; is really goddamn
annoying.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not everything needs a spec&amp;mdash;actually, &lt;em&gt;very few things need a spec.&lt;/em&gt; But
trying to build the fundamentals of interoperability without a spec and an open
process is&amp;mdash;like Ruby 1.8.7&amp;mdash;bound to fail.&lt;/p&gt;

&lt;h2&gt;tl;dr&lt;/h2&gt;

&lt;p&gt;The path to success for a Ruby library and a JSR are the same: pick a problem
where diversity of interface poses a problem, extract a common solution, get a
bunch of feedback from &lt;del&gt;stakeholders&lt;/del&gt;interested people in the
community who are working in the area, build a solid reference implementation
which people can easily use, build a test suite so implementers can red/green
their projects, and write a well-defined, simple spec.&lt;/p&gt;

&lt;p&gt;It worked for &lt;a href="http://jcp.org/en/jsr/detail?id=315"&gt;servlets&lt;/a&gt;,
it worked for &lt;a href="http://jcp.org/en/jsr/detail?id=220"&gt;Hibernate&lt;/a&gt;,
it&amp;rsquo;s working for &lt;a href="http://jcp.org/en/jsr/detail?id=311"&gt;Restlet&lt;/a&gt;,
it&amp;rsquo;s working for &lt;a href="http://jcp.org/en/jsr/detail?id=310"&gt;Joda Time&lt;/a&gt;,
it&amp;rsquo;ll work for &lt;a href="http://docs.google.com/Doc?id=dd2fhx4z_13cw24s7dj"&gt;Spring and Guice&lt;/a&gt;,
and it worked for Rack.&lt;/p&gt;

			&lt;p&gt;(This was posted at &lt;a href="http://codahale.com/when-formality-works/"&gt;codahale.com&lt;/a&gt;.)&lt;/p&gt;
		&lt;img src="http://feeds.feedburner.com/~r/codahale/~4/Wnp8aBuGXeA" height="1" width="1"/&gt;</content>
	<feedburner:origLink>http://codahale.com/when-formality-works/</feedburner:origLink></entry>
	
	<entry>
		<title>What Makes Jersey Interesting: Parameter Classes</title>
		<link href="http://feedproxy.google.com/~r/codahale/~3/pnL1YBIAM5E/" />
		<updated>2009-05-02T00:00:00+02:00</updated>
		<id>http://codahale.com/what-makes-jersey-interesting-parameter-classes</id>
		<content type="html">
			&lt;p&gt;For folks who have known me for a while, this may come as a bit of a shock:
these days I&amp;rsquo;m spending a &lt;em&gt;lot&lt;/em&gt; of time working with Java. And I&amp;rsquo;m having a
&lt;em&gt;lot&lt;/em&gt; of fun.&lt;/p&gt;

&lt;h2&gt;lol wut&lt;/h2&gt;

&lt;p&gt;No really.&lt;/p&gt;

&lt;p&gt;This is due in no small part to the fact that I&amp;rsquo;m working on writing RESTful
web services using a really neat framework:
&lt;a href="https://jersey.dev.java.net/"&gt;Jersey&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;What Is This Jersey You Speak Of&lt;/h2&gt;

&lt;p&gt;Jersey is the reference implementation  of
&lt;a href="https://jsr311.dev.java.net/"&gt;JSR311&lt;/a&gt;, which is the Java community&amp;rsquo;s incredibly
bureaucratic way of coming up with a decent API for writing RESTful web
services. Despite the gray-flannel-suit feel to it, it&amp;rsquo;s actually a delight to
work with.&lt;/p&gt;

&lt;p&gt;Broadly speaking, Jersey maps resources to classes, and HTTP verbs to methods.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s an example resource class:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/helloworld&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloWorldResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@GET&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;sayHello&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Hello, world!&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;@Path&lt;/code&gt; annotation marks the class as a resource class and tells Jersey what
URIs the resource is responsible for. When a request comes in for &lt;code&gt;/helloworld&lt;/code&gt;,
Jersey routes that to a &lt;code&gt;HelloWorldResource&lt;/code&gt; instance.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@Produces&lt;/code&gt; annotation allows Jersey to perform content negotiation. If a
request comes in with a &lt;code&gt;Accept: image/jpeg&lt;/code&gt; header, Jersey will respond with a
&lt;code&gt;406 Not Acceptable&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@GET&lt;/code&gt; annotation tells Jersey that the &lt;code&gt;sayHello()&lt;/code&gt; method is responsible
for handling &lt;code&gt;GET&lt;/code&gt; requests. If a resource class doesn&amp;rsquo;t have a method to handle
an HTTP verb, Jersey will respond with a &lt;code&gt;405 Method Not Allowed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When a &lt;code&gt;GET&lt;/code&gt; request comes in, Jersey calls &lt;code&gt;sayHello()&lt;/code&gt;. The &lt;code&gt;String&lt;/code&gt; that&amp;rsquo;s
returned gets turned into an HTTP response entity, and you&amp;rsquo;re off to the races.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s a lot more to it, but that&amp;rsquo;s Jersey and JSR311 in a nutshell.&lt;/p&gt;

&lt;p&gt;What this article is about is how a Jersey application handles change&amp;mdash;you can
find anything about a framework which will look good on a slide but end up
sucking horribly in real life (see: Rails' &lt;code&gt;respond_to&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;For this article, I&amp;rsquo;m going to write a weekday calculator. You give it a date,
and it tells you what day of the week the day was (or will be) on. Not
super-useful, sure, but my boss won&amp;rsquo;t let me paste huge chunks of our source
code here; you&amp;rsquo;ll have to settle for a contrived example.&lt;/p&gt;

&lt;h2&gt;Round One: The Simplest Thing Possible&lt;/h2&gt;

&lt;p&gt;The first thing I&amp;rsquo;ll do is sketch out a skeleton resource class. Here&amp;rsquo;s a first
swing:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/v1/weekday/{date}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SkeletonWeekdayResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@GET&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getWeekday&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;date&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot; is on a ???.&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You&amp;rsquo;ll notice that the &lt;code&gt;getWeekday&lt;/code&gt; method takes an argument, &lt;code&gt;date&lt;/code&gt;, which is
annotated with &lt;code&gt;@PathParam&lt;/code&gt;. The &lt;code&gt;@PathParam&lt;/code&gt; annotation pulls the &lt;code&gt;date&lt;/code&gt;
variable from the resource&amp;rsquo;s URI template (&lt;code&gt;/v1/weekday/{date}&lt;/code&gt;), turns it into
a &lt;code&gt;String&lt;/code&gt;, and passes it to the &lt;code&gt;getWeekday&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s a sample request/response:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;GET /v1/weekday/20060714 HTTP/1.1
Host: localhost:8080
Accept: */*
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And our resource class responds with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: text/plain

20060714 is on a ???.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This isn&amp;rsquo;t much more complicated than &lt;code&gt;HelloWorldResource&lt;/code&gt;; we&amp;rsquo;re still in
could-be-crap-but-looks-good-on-a-slide territory. So let&amp;rsquo;s add the guts of the
resource&amp;mdash;date parsing and weekday calculation. Because Java&amp;rsquo;s &lt;code&gt;Calendar&lt;/code&gt; and
&lt;code&gt;Date&lt;/code&gt; classes are &lt;em&gt;hilariously&lt;/em&gt; bad, I&amp;rsquo;m going to use
&lt;a href="http://joda-time.sourceforge.net/"&gt;Joda Time&lt;/a&gt;, which kicks ass.&lt;/p&gt;

&lt;h2&gt;Round Two: Now Make It Work&lt;/h2&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/v2/weekday/{date}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NaiveWeekdayResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;DateTimeFormatter&lt;/span&gt; &lt;span class="n"&gt;ISO_BASIC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ISODateTimeFormat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;basicDate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  
  &lt;span class="nd"&gt;@GET&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getWeekday&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;date&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;dateAsString&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ISO_BASIC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseDateTime&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateAsString&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dateAsString&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot; is on a &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dayOfWeek&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getAsText&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The changes here are obvious: we use &lt;code&gt;ISO_BASIC&lt;/code&gt;, a parser and formatter, to
turn &lt;code&gt;dateAsString&lt;/code&gt; into a &lt;code&gt;DateTime&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;. &lt;code&gt;date.dayOfWeek()&lt;/code&gt; returns a
property which we turn into text and send back to the client.&lt;/p&gt;

&lt;p&gt;Now it does what we want:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;GET /v2/weekday/20060714 HTTP/1.1
Host: localhost:8080
Accept: */*
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And then:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: text/plain

20060714 is on a Friday.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But this could still be a Potemkin application. So let&amp;rsquo;s do something you
rarely see in slide shows. Let&amp;rsquo;s throw some bad input at it.&lt;/p&gt;

&lt;h2&gt;Round Three: Oh Yeah, Error Handling&lt;/h2&gt;

&lt;p&gt;What happens when someone asks for an invalid date?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;GET /v2/weekday/200607f14 HTTP/1.1
Host: localhost:8080
Accept: */*
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Oh geez:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;HTTP/1.1 500 Invalid format: "200607f14" is malformed at "f14"
Content-Type: text/html; charset=iso-8859-1

&amp;lt;big-ass stack trace complaining about the date&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s not terrible, but it needs to change.&lt;/p&gt;

&lt;p&gt;First, &lt;code&gt;500 Internal Server Error&lt;/code&gt;is the wrong response. The problem isn&amp;rsquo;t with
the server&amp;rsquo;s state, it&amp;rsquo;s with the request. A better response would be &lt;code&gt;400 Bad
Request&lt;/code&gt;&amp;mdash;that way the client knows not to retry the request, and we can add
an explanation of what about the request needs to change before it will be
acceptable.&lt;/p&gt;

&lt;p&gt;Second, unloading a stack trace on random passers-by is bad form. They don&amp;rsquo;t
care, and they probably shouldn&amp;rsquo;t know what kind of magic is behind the scenes.&lt;/p&gt;

&lt;p&gt;So let&amp;rsquo;s add some error handling:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/v3/weekday/{date}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BetterWeekdayResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;DateTimeFormatter&lt;/span&gt; &lt;span class="n"&gt;ISO_BASIC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ISODateTimeFormat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;basicDate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  
  &lt;span class="nd"&gt;@GET&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getWeekday&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;date&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;dateAsString&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ISO_BASIC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseDateTime&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dateAsString&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dateAsString&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot; is on a &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dayOfWeek&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getAsText&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IllegalArgumentException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WebApplicationException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;Response&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BAD_REQUEST&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Couldn&amp;#39;t parse date: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;dateAsString&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot; (&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This is a pretty simple approach&amp;mdash;catch the exception, and throw a
&lt;code&gt;WebApplicationException&lt;/code&gt; with an HTTP response explaining the problem. Jersey
catches the &lt;code&gt;WebApplicationException&lt;/code&gt; and sends the attached &lt;code&gt;Response&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s try that again:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;GET /v2/weekday/200607f14 HTTP/1.1
Host: localhost:8080
Accept: */*
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yay!&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;HTTP/1.1 400 Bad Request
Content-Type: text/plain

Couldn't parse date: 200607f14 (Invalid format: "200607f14" is malformed at "f14")
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ok, so our code is now correct and handles errors, but its readability has
suffered&amp;mdash;for two lines of domain-specific code, we have nine lines of error
handling. &lt;em&gt;Ruh-roh.&lt;/em&gt; If we continue with this approach, every date parsing
resource in the application will have its own error handling, which means a lot
of copying and pasting and testing the error handling and bugs, bugs, bugs.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s where Jersey starts to shine&amp;mdash;separation of concerns.&lt;/p&gt;

&lt;h2&gt;Round Four: Time To Clean&lt;/h2&gt;

&lt;p&gt;The trick here is to stop accepting &lt;code&gt;String&lt;/code&gt;s and start dealing with
domain-specific objects. We can do that easily due to the way that Jersey
handles the &lt;code&gt;@PathParam&lt;/code&gt; annotation.&lt;/p&gt;

&lt;p&gt;From the Jersey docs:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;The type of the annotated parameter, field or property must either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;li&gt;Be a primitive type.&lt;/li&gt;
&lt;li&gt;Have a constructor that accepts a single &lt;code&gt;String&lt;/code&gt; argument.&lt;/li&gt;
&lt;li&gt;Have a static method named &lt;code&gt;valueOf&lt;/code&gt; that accepts a single &lt;code&gt;String&lt;/code&gt;
argument (see, for example, &lt;code&gt;Integer#valueOf(String)&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;So we can just write a class which takes a single &lt;code&gt;String&lt;/code&gt; argument, eh?&lt;/p&gt;

&lt;p&gt;Like this:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleDateParam&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;DateTimeFormatter&lt;/span&gt; &lt;span class="n"&gt;ISO_BASIC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ISODateTimeFormat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;basicDate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;originalValue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;SimpleDateParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="n"&gt;WebApplicationException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;originalValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ISO_BASIC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseDateTime&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IllegalArgumentException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WebApplicationException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;Response&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BAD_REQUEST&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Couldn&amp;#39;t parse date: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot; (&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="nf"&gt;getDate&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getOriginalValue&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;originalValue&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This is a pretty straight-forward class which takes a string, parses it, and
either throws a &lt;code&gt;WebApplicationException&lt;/code&gt; or returns an object with a &lt;code&gt;DateTime&lt;/code&gt;
and the original parameter.&lt;/p&gt;

&lt;p&gt;We can change our resource class to accept a &lt;code&gt;SimpleDateParam&lt;/code&gt; argument instead
of a &lt;code&gt;String&lt;/code&gt;, which ends up looking like this:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/v4/weekday/{date}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AwesomeWeekdayResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@GET&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getWeekday&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;date&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;SimpleDateParam&lt;/span&gt; &lt;span class="n"&gt;dateParam&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dateParam&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOriginalValue&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot; is on a &amp;quot;&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;dateParam&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDate&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;dayOfWeek&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getAsText&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Now that&amp;rsquo;s nice.&lt;/p&gt;

&lt;p&gt;In between our first working resource and this one, we&amp;rsquo;ve done a few things
worth noting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We extracted date parsing and HTTP-specific error handling into a simple,
testable, reusable class.&lt;/li&gt;
&lt;li&gt;We made our resource classes more testable. Instead of banging &lt;code&gt;String&lt;/code&gt;s
together and testing error handling, we can pass in &lt;code&gt;SimpleDateParam&lt;/code&gt; stubs
test the actual resource logic, safe in the knowledge that a malformed
&lt;code&gt;SimpleDateParam&lt;/code&gt; &lt;strong&gt;cannot exist&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;We made our web service a better HTTP citizen. Instead of freaking out with a
&lt;code&gt;500 THE BEES THEY'RE IN MY EYES&lt;/code&gt; mystery response, we provide clients and
intermediaries with specific, usable information.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;But wait! We&amp;rsquo;re not done yet!&lt;/p&gt;

&lt;h2&gt;Round Five: And &lt;em&gt;Stay&lt;/em&gt; Solved, Damnit&lt;/h2&gt;

&lt;p&gt;We can safely assume we&amp;rsquo;ll be writing a &lt;em&gt;lot&lt;/em&gt; of these param classes for any
given project&amp;mdash;in fact, the more of these we write, the cleaner and more
testable our resources are.&lt;/p&gt;

&lt;p&gt;Think about it&amp;mdash;does your web service accept any of the following things?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;URIs&lt;/li&gt;
&lt;li&gt;Numbers&lt;/li&gt;
&lt;li&gt;Enums (e.g., &lt;code&gt;/posts?status=1&lt;/code&gt; ends up being &lt;code&gt;PostStatus.ACTIVE&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Booleans&lt;/li&gt;
&lt;li&gt;Timestamps&lt;/li&gt;
&lt;li&gt;IDs with a specific format&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Duh. Of course it does. Now how many times do want to write that code? Once. So
it behooves us to streamline the param-writing process as much as possible.&lt;/p&gt;

&lt;p&gt;Thus:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AbstractParam&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;originalParam&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;AbstractParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="n"&gt;WebApplicationException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;originalParam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Throwable&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;WebApplicationException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt; &lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getOriginalParam&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;originalParam&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  
  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  
  &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="n"&gt;Throwable&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  
  &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="nf"&gt;onError&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Throwable&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BAD_REQUEST&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getErrorMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
  
  &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getErrorMessage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Throwable&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;Invalid parameter: &amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot; (&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getMessage&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Which means our param class ends up look like this:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DateParam&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;AbstractParam&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;DateTimeFormatter&lt;/span&gt; &lt;span class="n"&gt;ISO_BASIC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ISODateTimeFormat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;basicDate&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
  
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;DateParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="n"&gt;WebApplicationException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@Override&lt;/span&gt;
  &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="n"&gt;Throwable&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ISO_BASIC&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseDateTime&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;And our resource class looks like this:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;code class="java"&gt;&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/v5/weekday/{date}&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TEXT_PLAIN&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FinalWeekdayResource&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@GET&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;getWeekday&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@PathParam&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;date&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;DateParam&lt;/span&gt; &lt;span class="n"&gt;dateParam&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dateParam&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getOriginalParam&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot; is on a &amp;quot;&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;dateParam&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;dayOfWeek&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getAsText&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;tl;dr&lt;/h2&gt;

&lt;p&gt;Jersey&amp;rsquo;s approach to handling input is graceful in the face of ugly error
handling and edge cases, allowing separation of concerns, encapsulation, and
reuse. We started out with a simple resource class, added some functionality,
added some ugly error handling, then extracted that into a small, composed,
testable class. Any other resource class which needs to parse an ISO 8601 basic
date? &lt;em&gt;Solved.&lt;/em&gt; The end result is testable and readable.&lt;/p&gt;

&lt;p&gt;All this despite the fact that it&amp;rsquo;s in Java.&lt;/p&gt;

&lt;p&gt;You can download all the source code for this project
&lt;a href="/downloads/jersey-parameter-example.zip"&gt;here&lt;/a&gt;.&lt;/p&gt;

			&lt;p&gt;(This was posted at &lt;a href="http://codahale.com/what-makes-jersey-interesting-parameter-classes/"&gt;codahale.com&lt;/a&gt;.)&lt;/p&gt;
		&lt;img src="http://feeds.feedburner.com/~r/codahale/~4/pnL1YBIAM5E" height="1" width="1"/&gt;</content>
	<feedburner:origLink>http://codahale.com/what-makes-jersey-interesting-parameter-classes/</feedburner:origLink></entry>
	
</feed>

