Dinomite.netDrew Stephenshttp://dinomite.net/blog2017-07-15T11:20:00-04:00Drew StephensKotlin's let()http://dinomite.net/blog/2017/07/15/kotlin-s-let/2017-07-15T11:20:00-04:002017-07-15T11:30:40-04:00Drew Stephens<p>Kotlin’s standard library is a <a href="http://beust.com/weblog/2015/10/30/exploring-the-kotlin-standard-library/">small collection</a> of syntax sugar methods that are part of why the language is <a href="https://medium.com/@magnus.chatt/why-you-should-totally-switch-to-kotlin-c7bbde9e10d5">a better Java</a>. The <code>let()</code> function creates a block within which the receiver is scoped, either as Kotlin’s default <code>it</code> or a named variable you provide. Combined with Kotlin’s <a href="https://kotlinlang.org/docs/reference/null-safety.html#safe-calls">safe call operator</a>, only executing a block when you have a non-null value is concise:</p>
<div class="highlight plaintext"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3</pre></td><td class="code"><pre> dao.user(id)?.let {
// Do something with the user
}
</pre></td></tr></tbody></table>
</div>
<p>Cédric Beust has a <a href="http://beust.com/weblog/2016/01/14/a-close-look-at-kotlins-let/">follow-up post on <code>let()</code></a> in which he says that he is moving away from this usage of <code>?.let()</code> in favor of regular old <code>if-else</code> blocks because they make it more obvious what happens on the failing side of the <code>if</code>, when the result of the receiver is null. I agree, but have one style of function for which I still quite like <code>?.let()</code>—cache retrieval:</p>
<div class="highlight plaintext"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11</pre></td><td class="code"><pre> fun getSomethingExpensive(id: Int): String? {
val cacheKey = "cache:$id"
jedis.get(cacheKey)?.let { return it }
// No cached value, do the work
val result = someExpensiveWorkFunction()
jedis.setex(cacheKey, result)
return result
}
</pre></td></tr></tbody></table>
</div>
<p>I like the flow of this style; you pause to check the cache, but move on to computing the value immediately below without the extra visual complexity of assigning the result of the cache query to variable and separately checking that variable for being null.</p>
Coding Testshttp://dinomite.net/blog/2017/07/12/coding-tests/2017-07-12T08:17:00-04:002017-07-12T12:58:12-04:00Drew Stephens<p>Hiring for developers is tricky business for many reasons, but one of the most contentious is assessing technical ability. Anyone who has done hiring, in particular for junior developers, has come across <a href="https://blog.codinghorror.com/why-cant-programmers-program/">candidates that couldn’t write the simplest of programs</a>. Thus we find ourselves in a world where technical interviews often involve whiteboard coding or coding tests.</p>
<h1>Whiteboard Coding</h1>
<p>The short summary: whiteboard coding is almost always a bad idea—it doesn’t really assess what you’re looking for.</p>
<p>Many interviewers, who either haven’t ever experienced whiteboard coding or who themselves possess exceptional social fortitude, think that whiteboard coding is a great way to assess a candidate’s programming ability and see how they think. Unfortunately, the unnaturalness of writing code in a stressful situation, by hand, with an audience, without being able to test it leaves many developers in a flustered state unable to think.</p>
<p>A year after college I was working at a job I slid into by way of prior internships. I hadn’t ever actually interviewed for a technical job. I wanted something more challenging and interesting than that position, so I applied to Google. After phone screens they invited me on site. The second interview was with a pair of programmers who wanted me to do something simple, akin to <a href="http://wiki.c2.com/?FizzBuzzTest">FizzBuzz</a>.</p>
<p>I was incredibly flustered—I knew modular division was what was required but that wasn’t something I had done since CS1 (note: I have more fingers than times I’ve employed modular division now, in 10 years of professional software engineering). Even though it’s a trivial problem, even with very little experience, my initial surprise completely subverted my ability to even start thinking about the program critically. I started just writing things on the board and eventually stumbled through the exercise but it was clear that was the last interview.</p>
<h1>Live Coding</h1>
<p>“<em>Ah-ha!</em>”, you think, “<em>I’ll give them a great setup to eliminate the unnatural situation of coding by hand on a whiteboard! We’ll have an interviewee laptop that they can use with the best IDE!</em>”. That’s a great step, but doesn’t solve the biggest problem: the audience. Programming is a largely solitary activity, especially for more junior engineers. I definitely think that collaboration and things like pair programming are important, but to pretend that such a lopsided, I’m-evaluating-you-right-now arrangement is at all like pair programming is to <a href="https://www.youtube.com/watch?v=dYBjVTMUQY0">completely misunderstand what the paradigm is about</a>.</p>
<p>Beyond that, know that the technical environment you are providing is invariably unnatural as well. Developers may only have experience on Windows and you provide them with a Mac. They might work in an IDE like WebStorm or Eclipse and your setup is Sublime with a terminal. Those problems are significant enough to leave even the best developer in a state of confusion, which begets sheer terror in the interview context, but we haven’t even gotten to the biggest problem.</p>
<p>If you expect a developer to be able to write code in such a stressful situation the only way they will be successful and not look completely daft to even a casual observer is to allow them to write in a language that they currently use. That doesn’t mean anything from their resume, or what your company is hiring them to write, that means a language that they have actively used in the past week or two. Working in multiple languages involves a switching period to bring the correct syntax to mind—that can be a few minutes if you’ve only been out of it for a week, but can easily be tens of minutes filled with repeated web searches for the most trivial language constructs (<code>else if</code> or <code>elsif</code>? how do I for-each?). Realize that forcing a developer to ask such basic questions both poisons your opinion of them (shouldn’t you at least know <em>that</em>?) and puts them in a dreadful state of mind (I couldn’t even remember <em>that</em>!).</p>
<p>Finally, as we’ll get to later, any sort of coding test requires significant up-front effort on the company’s part.</p>
<h1>Take-home coding tests</h1>
<p>A take-home coding test solves all of the aforementioned problems. Candidates get to use an devlopment environment of their preference, aren’t under live scrutiny, and get to work in the manner that is best for them. For all of these reasons, I quite like take-home coding tests, but they rightly get a lot of hate from other developers for a few reasons.</p>
<h2>Time</h2>
<p>The exercise needs to be time limited and of a reasonable scope, <strong>3-5 hours at most</strong>. That doesn’t mean saying “don’t spend more than 3-5 hours on this” in your description. I’ve seen many coding tests that stipulate a time limit, but also mention that applicants will be graded on tests, error handling, dealing with unexpected input, and documentation. Even when applied to a very small project, those tasks alone can comprise 3-5 hours of work. It is not reasonable to ask a developer applying to your company to spend more than 2-3 hours, with a very maximum cap of five, working on your test. If nothing else, you’re going to lose nearly all of them to companies without such onerous requirements.</p>
<h2>Expectations</h2>
<p>Having realistic and flexible expectations is paramount. No matter the developer’s level of experience, how you’re querying them, or how thorough your explanation, without the ability to ask questions in real-time <strong>your test will be misunderstood</strong>.</p>
<p>“<em>But we’re a consulting shop! Our developers have to build precisely what the customer needs from a spec all the time!</em>” you protest. Doesn’t matter—the candidate isn’t part of your work environment, hasn’t met the customer, and is working on a contrived project of highly limited scope. A coding test isn’t a good way to thoroughly test developer’s abilities to understand and implement specs.</p>
<p>Some will implement a totally working solution that misses the point. Others will have a great implementation but only a single simple test. For an otherwise good candidate, neither of these should be deal breakers and you absolutely shouldn’t decline them without talking to them. <strong>Schedule a call and talk to them about how they approached the problem</strong>, their interpretation of it, and what steps they took in building their solution.</p>
<h1>Doing it right</h1>
<h2>Take-home coding tests</h2>
<p>For junior developers, your coding test should be at the very least a full project setup: in Java land that means a <code>pom.xml</code> or <code>build.gradle</code> already stubbed out and a main method ready to receive the candidate’s code. In Ruby you might stub out the main script with calls to a class that the candidate is to write, along with a <code>Gemfile</code> if they’re expected to use any Gems. There are many great junior developers who haven’t ever started a new project.</p>
<p>Better than that, though, is to write out the entirety of the app, save for a couple of unimplemented methods or a stubbed class which the candidate is to complete. You might provide a suite of failing test cases in the framework but if not you should go ahead and create the files & classes required. See <a href="https://github.com/adhocteam/homework/tree/master/fetch">this example</a> from <a href="https://adhocteam.us">Ad Hoc</a>.</p>
<p>For more senior developers, it is ok to leave things much more open ended—it shouldn’t be beyond a senior developer’s skill to choose & create the layout of their project. Because it is more open ended, however, there is a much more significant burden on the company to ensure that the description of the test is comprehensive and clear. You need to provide the candidate with test input & output (more than just one parcel) that they can understand what you’re looking for. Being senior doesn’t mean they can read your mind.</p>
<p>How do you know if you’ve met the above? <strong>Have one of your engineers who wasn’t involved at all in the creation take the test</strong> and see how they do, both on time and how their peers evaluate the result. Needless to say, this should be on the clock—this person is your employee, not a candidate.</p>
<h2>Live coding</h2>
<p>For live coding, regardless of level, the arrangement should be the most fleshed-out description for junior developers above: <strong>a fully written app with a few unimplemented methods or classes that the candidate is to fill in</strong>. If they’re going to need helper methods (to parse input or some such) provide them. Again, for junior developers provide at least some tests; ask them what others they would add.</p>
<p>Here’s where the real burden comes in: you need this framework for a language that the candidate is accustomed to, even if it’s not the language you’re hiring for. Most companies hire developers even if they don’t regularly program in the language used at the company and a developer can only be exptected to work effectively in a language that they use regularly. You should have frameworks prepared for common languages—Java, Ruby, Python, and JavaScript is a good start for a webdev shop. If you’re more backend focused, C & Go probably replace JS. More frontend, add in Swift or Objective-C.</p>
<p>Know that this is still a risky proposition and you need to be understanding enough not fail a candidate just because they seem to have trouble, especially right when you start. Even with a fleshed out framework in their language of choice, remember that they’re not using a computer they’re used to and that they’re massively on display in what is normally an endeavor done alone or with someone you already know well.</p>
<h2>Whiteboard coding</h2>
<p>Whiteboard coding isn’t a good idea, especially for junior developers. A whiteboard coding session is more likely to select for confidence in demanding social situations than those with programming aptitude.</p>
<p>For senior developers, however, whiteboarding at a higher level (architecture) is a great interview tool. Describe to the candidate some real problem that your team had and ask them how they would solve it. Be prepared to give copious hints and don’t mark down candidates who need that help—it is very easy for a stressed-out candidate to misinterpret your question, even just the complexity level you’re going for, and be completely caught off guard.</p>
JDBI Tipshttp://dinomite.net/blog/2017/01/19/jdbi-tips/2017-01-18T19:00:00-05:002017-01-19T11:20:17-05:00Drew Stephens<p>I’ve been using <a href="http://jdbi.org/">JDBI</a> in Java & <a href="https://kotlinlang.org/">Kotlin</a> projects recently and have come across a few things that aren’t entirely intuitive. If you’re having trouble with JDBI, be sure to check <a href="http://jdbi.org/archive.html">the docs</a>; if you don’t find an answer there, the <a href="https://github.com/jdbi/jdbi/issues">issues on GitHub</a> is a great place to look for more esoteric uses of the library.</p>
<h1>Guice</h1>
<p>I have a Dropwizard app that I use with Guice via <a href="https://github.com/xvik/dropwizard-guicey">dropwizard-guicey</a>. While the <a href="http://www.dropwizard.io/1.0.0/docs/manual/jdbi.html">Dropwizard docs</a> cover using JDBI, constructing instances is a bit different with dropwizard-guicey. My (Kotlin) module for registering DAOs looks like this:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18</pre></td><td class="code"><pre><span class="kd">class</span> <span class="nc">DaoModule</span> <span class="o">:</span> <span class="n">DropwizardAwareModule</span><span class="o"><</span><span class="n">AppConfiguration</span><span class="o">>()</span> <span class="o">{</span>
<span class="n">override</span> <span class="n">fun</span> <span class="n">configure</span><span class="o">()</span> <span class="o">{</span>
<span class="n">val</span> <span class="n">factory</span> <span class="o">=</span> <span class="n">AppDBIFactory</span><span class="o">()</span>
<span class="n">val</span> <span class="n">dataSourceFactory</span> <span class="o">=</span> <span class="n">configuration</span><span class="o">().</span><span class="na">dataSourceFactory</span>
<span class="n">val</span> <span class="n">jdbi</span> <span class="o">=</span> <span class="n">factory</span><span class="o">.</span><span class="na">build</span><span class="o">(</span><span class="n">environment</span><span class="o">(),</span> <span class="n">dataSourceFactory</span><span class="o">,</span> <span class="s">"postgresql"</span><span class="o">)</span>
<span class="n">jdbi</span><span class="o">.</span><span class="na">registerArgumentFactory</span><span class="o">(</span><span class="n">PgIntegerArrayArgFactory</span><span class="o">())</span>
<span class="n">bind</span><span class="o">(</span><span class="nl">DBI:</span><span class="o">:</span><span class="kd">class</span><span class="err">.</span><span class="nc">java</span><span class="o">).</span><span class="na">toInstance</span><span class="o">(</span><span class="n">jdbi</span><span class="o">)</span>
<span class="n">val</span> <span class="n">apiKeyDao</span> <span class="o">=</span> <span class="n">jdbi</span><span class="o">.</span><span class="na">onDemand</span><span class="o">(</span><span class="nl">ApiKeyDao:</span><span class="o">:</span><span class="kd">class</span><span class="err">.</span><span class="nc">java</span><span class="o">)</span>
<span class="n">bind</span><span class="o">(</span><span class="nl">ApiKeyDao:</span><span class="o">:</span><span class="kd">class</span><span class="err">.</span><span class="nc">java</span><span class="o">).</span><span class="na">toInstance</span><span class="o">(</span><span class="n">apiKeyDao</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">class</span> <span class="nc">AppDBIFactory</span> <span class="o">:</span> <span class="n">DBIFactory</span><span class="o">()</span> <span class="o">{</span>
<span class="n">override</span> <span class="n">fun</span> <span class="n">databaseTimeZone</span><span class="o">():</span> <span class="n">Optional</span><span class="o"><</span><span class="n">TimeZone</span><span class="o">>?</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">Optional</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="n">TimeZone</span><span class="o">.</span><span class="na">getTimeZone</span><span class="o">(</span><span class="s">"UTC"</span><span class="o">))</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<p>More on the <code>PgIntegerArrayArgFactory</code> below.</p>
<h1>Querying Enums</h1>
<p>JDBI’s default binding of <code>enum</code> arguments <a href="https://github.com/jdbi/jdbi/blob/292b089cfd4e6a6f5f41c9bd320bade1f66926da/src/main/java/org/skife/jdbi/v2/EnumArgument.java#L37">calls <code>.name()</code></a> on the enum object. I have enums that instead use the ordinal value in a numeric database column, so I need the binding to call <code>.ordinal()</code> instead. To accomplish this, I create a special binding factory, which looks a bit nasty, but it’s actual action is quite straighforward:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14</pre></td><td class="code"><pre><span class="nd">@BindingAnnotation</span><span class="o">(</span><span class="n">BindStatus</span><span class="o">.</span><span class="na">StatusBinderFactory</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="nd">@Retention</span><span class="o">(</span><span class="n">RetentionPolicy</span><span class="o">.</span><span class="na">RUNTIME</span><span class="o">)</span>
<span class="nd">@Target</span><span class="o">({</span><span class="n">ElementType</span><span class="o">.</span><span class="na">PARAMETER</span><span class="o">})</span>
<span class="kd">public</span> <span class="nd">@interface</span> <span class="n">BindWidgetStatus</span> <span class="o">{</span>
<span class="kd">class</span> <span class="nc">StatusBinderFactory</span> <span class="kd">implements</span> <span class="n">BinderFactory</span> <span class="o">{</span>
<span class="kd">public</span> <span class="n">Binder</span> <span class="n">build</span><span class="o">(</span><span class="n">Annotation</span> <span class="n">annotation</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">Binder</span><span class="o"><</span><span class="n">BindStatus</span><span class="o">,</span> <span class="n">Status</span><span class="o">>()</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="n">bind</span><span class="o">(</span><span class="n">SQLStatement</span> <span class="n">q</span><span class="o">,</span> <span class="n">BindStatus</span> <span class="n">bind</span><span class="o">,</span> <span class="n">Status</span> <span class="n">arg</span><span class="o">)</span> <span class="o">{</span>
<span class="n">q</span><span class="o">.</span><span class="na">bind</span><span class="o">(</span><span class="s">"status"</span><span class="o">,</span> <span class="n">arg</span><span class="o">.</span><span class="na">ordinal</span><span class="o">());</span>
<span class="o">}</span>
<span class="o">};</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<p>The operative part is down in the deepest indentation—bind the ordinal value of the enum to whatever you will use as the placeholder string in the query. Then, in the DAO:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5</pre></td><td class="code"><pre><span class="nd">@RegisterMapper</span><span class="o">(</span><span class="nl">WidgetMapper:</span><span class="o">:</span><span class="kd">class</span><span class="err">)</span>
<span class="nc">interface</span> <span class="n">WidgetDao</span> <span class="o">{</span>
<span class="nd">@SqlQuery</span><span class="o">(</span><span class="s">"SELECT * FROM widgets WHERE status = :status "</span><span class="o">)</span>
<span class="n">fun</span> <span class="n">getWidgets</span><span class="o">(</span><span class="nd">@BindWidgetStatus</span> <span class="nl">status:</span> <span class="n">Widget</span><span class="o">.</span><span class="na">Status</span><span class="o">):</span> <span class="n">List</span><span class="o"><</span><span class="n">Widget</span><span class="o">></span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<p>Be sure to use the same placeholder string as in the <code>BinderFactory</code> above (in this case <code>status</code>).</p>
<h1>Array arguments</h1>
<p>Sometimes I want to be able to select widgets in any <code>Status</code>. In SQL, I would use an <code>IN</code> clause: “<code>...WHERE status IN (0, 1, 2)</code>” and, with a bit more setup JDBI can do the same. First, the enum in question:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13</pre></td><td class="code"><pre><span class="n">data</span> <span class="kd">class</span> <span class="nf">Widget</span><span class="p">(</span><span class="n">val</span> <span class="nl">id:</span> <span class="n">Int</span><span class="o">,</span> <span class="n">val</span> <span class="nl">status:</span> <span class="n">Status</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">enum</span> <span class="kd">class</span> <span class="nc">Status</span> <span class="o">{</span>
<span class="n">UNREAD</span><span class="o">,</span> <span class="n">READ</span><span class="o">,</span> <span class="n">ALL</span><span class="o">;</span>
<span class="n">fun</span> <span class="n">queryValue</span><span class="o">():</span> <span class="n">Array</span><span class="o"><</span><span class="n">Int</span><span class="o">></span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="k">this</span> <span class="o">==</span> <span class="n">ALL</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">arrayOf</span><span class="o">(</span><span class="n">UNREAD</span><span class="o">.</span><span class="na">ordinal</span><span class="o">,</span> <span class="n">READ</span><span class="o">.</span><span class="na">ordinal</span><span class="o">)</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">arrayOf</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">ordinal</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<p>And change the <code>Binder</code> to use the <code>queryValue()</code> method:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14</pre></td><td class="code"><pre><span class="nd">@BindingAnnotation</span><span class="o">(</span><span class="n">BindStatus</span><span class="o">.</span><span class="na">StatusBinderFactory</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="nd">@Retention</span><span class="o">(</span><span class="n">RetentionPolicy</span><span class="o">.</span><span class="na">RUNTIME</span><span class="o">)</span>
<span class="nd">@Target</span><span class="o">({</span><span class="n">ElementType</span><span class="o">.</span><span class="na">PARAMETER</span><span class="o">})</span>
<span class="kd">public</span> <span class="nd">@interface</span> <span class="n">BindWidgetStatus</span> <span class="o">{</span>
<span class="kd">class</span> <span class="nc">StatusBinderFactory</span> <span class="kd">implements</span> <span class="n">BinderFactory</span> <span class="o">{</span>
<span class="kd">public</span> <span class="n">Binder</span> <span class="n">build</span><span class="o">(</span><span class="n">Annotation</span> <span class="n">annotation</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">Binder</span><span class="o"><</span><span class="n">BindStatus</span><span class="o">,</span> <span class="n">Status</span><span class="o">>()</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="n">bind</span><span class="o">(</span><span class="n">SQLStatement</span> <span class="n">q</span><span class="o">,</span> <span class="n">BindStatus</span> <span class="n">bind</span><span class="o">,</span> <span class="n">Status</span> <span class="n">arg</span><span class="o">)</span> <span class="o">{</span>
<span class="n">q</span><span class="o">.</span><span class="na">bind</span><span class="o">(</span><span class="s">"status"</span><span class="o">,</span> <span class="n">SqlArray</span><span class="o">.</span><span class="na">arrayOf</span><span class="o">(</span><span class="n">Integer</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">arg</span><span class="o">.</span><span class="na">queryValue</span><span class="o">()));</span>
<span class="o">}</span>
<span class="o">};</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<p>That <code>SqlArray</code> is a just a POJO for holding the things to be bound:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22</pre></td><td class="code"><pre><span class="kd">class</span> <span class="nc">SqlArray</span><span class="o"><</span><span class="n">T</span><span class="o">></span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">Object</span><span class="o">[]</span> <span class="n">elements</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">Class</span><span class="o"><</span><span class="n">T</span><span class="o">></span> <span class="n">type</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">SqlArray</span><span class="o">(</span><span class="n">Class</span><span class="o"><</span><span class="n">T</span><span class="o">></span> <span class="n">type</span><span class="o">,</span> <span class="n">Collection</span><span class="o"><</span><span class="n">T</span><span class="o">></span> <span class="n">elements</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">elements</span> <span class="o">=</span> <span class="n">Iterables</span><span class="o">.</span><span class="na">toArray</span><span class="o">(</span><span class="n">elements</span><span class="o">,</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="k">this</span><span class="o">.</span><span class="na">type</span> <span class="o">=</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@SafeVarargs</span>
<span class="kd">static</span> <span class="o"><</span><span class="n">T</span><span class="o">></span> <span class="n">SqlArray</span><span class="o"><</span><span class="n">T</span><span class="o">></span> <span class="n">arrayOf</span><span class="o">(</span><span class="n">Class</span><span class="o"><</span><span class="n">T</span><span class="o">></span> <span class="n">type</span><span class="o">,</span> <span class="n">T</span><span class="o">...</span> <span class="n">elements</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">SqlArray</span><span class="o"><>(</span><span class="n">type</span><span class="o">,</span> <span class="n">asList</span><span class="o">(</span><span class="n">elements</span><span class="o">));</span>
<span class="o">}</span>
<span class="n">Object</span><span class="o">[]</span> <span class="n">getElements</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">elements</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">Class</span><span class="o"><</span><span class="n">T</span><span class="o">></span> <span class="n">getType</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<p>Finally, also in Java, an <code>ArgumentFactory</code> to bind the SqlArray values:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16</pre></td><td class="code"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">PgIntegerArrayArgFactory</span> <span class="kd">implements</span> <span class="n">ArgumentFactory</span><span class="o"><</span><span class="n">SqlArray</span><span class="o"><</span><span class="n">Integer</span><span class="o">>></span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="n">accepts</span><span class="o">(</span><span class="n">Class</span><span class="o"><?></span> <span class="n">type</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">,</span> <span class="n">StatementContext</span> <span class="n">ctx</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">value</span> <span class="k">instanceof</span> <span class="n">SqlArray</span>
<span class="o">&&</span> <span class="o">((</span><span class="n">SqlArray</span><span class="o">)</span><span class="n">value</span><span class="o">).</span><span class="na">getType</span><span class="o">().</span><span class="na">isAssignableFrom</span><span class="o">(</span><span class="n">Integer</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">Argument</span> <span class="n">build</span><span class="o">(</span><span class="n">Class</span><span class="o"><?></span> <span class="n">type</span><span class="o">,</span>
<span class="kd">final</span> <span class="n">SqlArray</span><span class="o"><</span><span class="n">Integer</span><span class="o">></span> <span class="n">value</span><span class="o">,</span>
<span class="n">StatementContext</span> <span class="n">ctx</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="o">(</span><span class="n">position</span><span class="o">,</span> <span class="n">statement</span><span class="o">,</span> <span class="n">ctx1</span><span class="o">)</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">Array</span> <span class="n">ary</span> <span class="o">=</span> <span class="n">ctx1</span><span class="o">.</span><span class="na">getConnection</span><span class="o">()</span>
<span class="o">.</span><span class="na">createArrayOf</span><span class="o">(</span><span class="s">"integer"</span><span class="o">,</span> <span class="n">value</span><span class="o">.</span><span class="na">getElements</span><span class="o">());</span>
<span class="n">statement</span><span class="o">.</span><span class="na">setArray</span><span class="o">(</span><span class="n">position</span><span class="o">,</span> <span class="n">ary</span><span class="o">);</span>
<span class="o">};</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<p>This is described more thoroughly on <a href="http://skife.org/jdbi/java/2011/12/21/jdbi_in_clauses.html">Brian McCallister’s blog</a>. Note that he calls the above <code>ArgumentFactory</code> a toy, since it only binds one type (Integers). Since I only use integer array arguments so far, I’ve left it as such.</p>
<h1>Optional arguments</h1>
<p>Sometimes you want to have optional arguments in a DAO method, like an ID to start selecting records at. JDBI supports this, but in a non-intuitive way—you simply write the <code>@SqlQuery</code> to expect a possibly null value:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3</pre></td><td class="code"><pre> <span class="nd">@SqlQuery</span><span class="o">(</span><span class="s">"SELECT * FROM widgets "</span> <span class="o">+</span>
<span class="s">"WHERE (cast(:start_id AS INT) IS NULL OR c1.id <= :start_id)"</span><span class="o">)</span>
<span class="n">fun</span> <span class="n">widgets</span><span class="o">(</span><span class="nd">@Bind</span><span class="o">(</span><span class="s">"start_id"</span><span class="o">)</span> <span class="nl">startId:</span> <span class="n">Int</span><span class="o">?):</span> <span class="n">List</span><span class="o"><</span><span class="n">Widget</span><span class="o">></span>
</pre></td></tr></tbody></table>
</div>
<p>Since this is written in Kotlin, you can see that startId is nullable. If it is null the SQL query will ignore it (the <code>where</code> clause is always true). More details <a href="https://github.com/jdbi/jdbi/issues/381">here</a>.</p>
DIY Stretch Webbing Leash (à la Ruffwear® Roamer™)http://dinomite.net/blog/2016/09/23/diy-stretch-webbing-leash-a-la-ruffwear-roamer/2016-09-22T20:00:00-04:002017-01-08T13:00:44-05:00Drew Stephens<p><a href="https://www.flickr.com/photos/dinomite/29049432104/in/album-72157675204681913/"><img alt="Materials" src="https://farm9.staticflickr.com/8301/29049432104_dcfa623b0b_z_d.jpg" /></a></p>
<p>The <a href="https://www.amazon.com/Ruffwear-Roamer-Leash-Large-Obsidian/dp/B00HE4Y4RK/ref=as_li_ss_il?ie=UTF8&qid=1473815307&sr=8-1&keywords=ruffwear+roamer&linkCode=li2&tag=dinomitenet-20&linkId=fc8e0acc8fe28c14d2fcfcbb638bf137">Ruffwear® Roamer™</a> leash is wonderful for running and great for anytime when you have an enthusiastic dog who pulls or lurches after prey. The leash is made of tubular webbing with elastic down the center that keeps the length manageable while also softening the blows from your leash partner. Unfortunately, it isn’t very durable and the tension of the elastic is insufficient for strong dogs. My beagle-terrier-thing is only 30 pounds but is very strong and easily exceeded the Roamer™’s elastic, defeating much of the leash’s purpose. I figured I could do better.</p>
<h1>Materials</h1>
<p>In order to make a 6-8 foot leash, depending upon whether you’re wearing it as a belt or not, I started with a 10 foot length of <a href="https://www.amazon.com/BlueWater-Ropes-Climb-Spec%C2%AE-Webbing-Black/dp/B004AGOHT0/ref=as_li_ss_il?ie=UTF8&qid=1473815452&sr=8-1&keywords=tubular+webbing&linkCode=li2&tag=dinomitenet-20&linkId=89ba46ef5b0db13cedc54214709d81ab">one inch wide tubular webbing</a>. I used <a href="https://www.amazon.com/TheraBand-Professional-Resistance-Exercise-Conditioning/dp/B00066D654/ref=as_li_ss_il?ie=UTF8&qid=1473815413&sr=8-1&keywords=thera-band+tubing+special+heavy&linkCode=li2&tag=dinomitenet-20&linkId=4bbc12c473e8108df5d3fa6c7b50524a">Thera-Band surgical tubing</a> in the black “Special Heavy” strength, which provides ample resistance for very strong medium dogs and fits well down the center of one inch webbing. Use 40% as much surgical tubing as the stretch portion of your leash—in my case the stretch portion is 6½ feet (78 inches) so the lease has 32 inches of tubular webbing.</p>
<p>For the handle, a <a href="https://www.amazon.com/10-Adjustable-Release-Plastic-Buckles/dp/B00DCZRLZW/ref=as_li_ss_tl?ie=UTF8&qid=1473815767&sr=8-3&keywords=1+inch+side+release+buckle&linkCode=ll1&tag=dinomitenet-20&linkId=131e0096cc6f7c63b13d116703446a45">side-release buckle</a> allows you to use the leash both with a normal handle and as a belt. If you don’t care about being able to belt the leash, you could omit this and simply make a loop handle. I’ve had too many clips that open when the dog charges into a bush, so I use an <a href="https://www.amazon.com/Camp-5118103-Orbit-Twist-Carabiner/dp/B00372AVQ6/ref=as_li_ss_tl?ie=UTF8&qid=1473815910&sr=8-4&keywords=locking+carabiner+automatic&linkCode=ll1&tag=dinomitenet-20&linkId=c1772c822ed001e688afa5703ffcff25">automatic locking carabiner</a> for the dog end of the leash.</p>
<h1>Tools</h1>
<ul>
<li><a href="https://www.amazon.com/COATS-CLARK-Heavy-Thread-125-Yard/dp/B001MUFKNE/ref=as_li_ss_tl?ie=UTF8&qid=1473816090&sr=8-1&keywords=heavy+duty+thread&linkCode=ll1&tag=dinomitenet-20&linkId=51227a186ffe12d2493a05738ef348dd">Heavy duty thread</a></li>
<li><a href="https://www.amazon.com/Singer-Assorted-Hand-Needles-45-Count/dp/B002PI751C/ref=as_li_ss_tl?ie=UTF8&qid=1473816125&sr=8-1&keywords=sewing+needles&linkCode=ll1&tag=dinomitenet-20&linkId=2f4964461ba833be8c916f1499a3619f">Sewing needle</a></li>
<li>Scissors</li>
<li>Lighter or matches</li>
<li>¼ inch by 2-3 foot long metal rod</li>
<li>Binder clips</li>
</ul>
<h1>Construction</h1>
<p><a href="https://www.flickr.com/photos/dinomite/29594543561/in/album-72157675204681913/"><img alt="Threading" src="https://farm9.staticflickr.com/8186/29594543561_d7c4a4caa5_m_d.jpg" /></a></p>
<p>Getting the slack surgical tubing threaded through the webbing, with 2.5 times as much webbing bunched up along its length, was the most difficult part conceptually, but after some trial and error I came up with a very easy solution. I found a ¼" metal rod that fit very tightly into the surgical tubing’s center. Forcing an inch worth of the tubing down over the rod makes for enough friction that you can apply quite a lot of force and stretch the surgical tubing wihtout it coming free.</p>
<p>With this odd arrangment setup, begin by threading the dog-end of the tubular webbing over the metal rod, and keep threading until it meets up with the open end of the surgical tubing. When those ends are lined up, secure the elastic inside of the webbing with a binder clip. Then, it’s just a process of stretching the surgical tubing and feeding more webbing over the rod and onto the tubing with it taught. I fed 6½ feet of webbing onto my 32 inches of webbing, leaving the remaining 3½ feet of webbing for constructing the handle.</p>
<p>Once you have all of the webbing you want bunched up on the surgical tubing, grip the tubing through the webbing near where the rod is attached to the surgical tubing very tightly and pull the rod straight out of the surgical tubing. Now it’s time to sew.</p>
<p><a href="https://www.flickr.com/photos/dinomite/29385052030/in/album-72157675204681913/"><img alt="Binding the surgical tubing" src="https://farm9.staticflickr.com/8295/29385052030_38b1662bba_z_d.jpg" /></a></p>
<p>Sewing is the other important technique of this project. The surgical tubing, like most elastomers, doesn’t respond well to being cut or punctured, so it is important to avoid sending the needle through it whilst sewing. In order to keep the surgical tubing in place the technique I have settled on is crimping it tightly. Fold over the last inch of surgical tubing, and the webbing it is within, back onto itself. Secure the fold with a binder clip and then sew either side of the webbing tightly together about ¼ inch from the end of the tubing. Follow this with some stiches across the webbing. Remove hte binder clip and repeat near the folded end of the joint.</p>
<p>See the <a href="https://www.flickr.com/photos/dinomite/sets/72157675204681913">Flickr album</a> for more construction details.</p>
Optional Authentication with Dropwizardhttp://dinomite.net/blog/2016/05/18/optional-authentication-with-dropwizard/2016-05-17T20:00:00-04:002016-05-18T09:46:36-04:00Drew Stephens<p><a href="http://dropwizard.io">Dropwizard</a> provides a great framework for authentication & authorization. <a href="http://www.dropwizard.io/0.9.2/dropwizard-auth/apidocs/io/dropwizard/auth/Authenticator.html"><code>Authenticator</code></a>s do what their name implies, returning a <a href="http://docs.oracle.com/javase/7/docs/api/java/security/Principal.html?is-external=true"><code>Principal</code></a> (probably your <code>User</code> object) that servlets can use for building responses. The <a href="http://www.dropwizard.io/0.9.2/dropwizard-auth/apidocs/io/dropwizard/auth/Authorizer.html"><code>Authorizer</code></a> interface has a single methoed, <code>authorize()</code>, which takes a <code>Principal</code> and a string role to authorize access for. These get wrapped in an <a href="http://www.dropwizard.io/0.9.2/dropwizard-auth/apidocs/io/dropwizard/auth/AuthFilter.html"><code>AuthFilter</code></a> which extracts credentials from the requst and passed on to the <code>Authenticator</code>.</p>
<p>With the authen & authz classes in place protecting resources is easy: you simply annotate them with one of <code>@PermitAll</code>, <code>@RolesAllowed</code>, or <code>@DenyAll</code>. The last one does exactly what it says on the tin. A specific role or set of roles can be permitted access with the <code>@RolesAllowed</code> annotation, to which you pass a <code>String</code> or <code>String[]</code> of roles. <code>@PermitAll</code> allows any <em>authenticated</em> user to access the resource. What is missing here is an annotation to allow optionally authenticated resources—allowing you to customize a response for a known user but deliver a generic response to anonymous visitors.</p>
<h1>Optionally protected resources</h1>
<p>The Dropwizard manual gives a <a href="http://www.dropwizard.io/0.9.2/docs/manual/auth.html#protecting-resources">cursory explanation</a> of how to implement optional authentication:</p>
<p><tt>
If you have a resource which is optionally protected (e.g., you want to display a logged-in user’s name but not require login), you need to implement a custom filter which injects a security context containing the principal if it exists, without performing authentication.
</tt></p>
<p>The process for optional resources involves two <code>AuthFilter</code>s: one to check & process credentials for a logged-in user and a second that provides a default user. These can be hit in turn with a <a href="http://www.dropwizard.io/0.9.2/dropwizard-auth/apidocs/io/dropwizard/auth/chained/ChainedAuthFilter.html"><code>ChainedAuthFilter</code></a>.</p>
<p>I’ll show the important parts of how I accomplished this with code examples written in a mix of Java and <a href="https://kotlinlang.org/">Kotlin</a>.</p>
<h1>Wiring</h1>
<p>Setting up Dropwizard’s authentication involves creating an <code>AuthFilter</code> to which you pass the <code>Authenticator</code> and <code>Authorizer</code> that it will use. Creating a <code>ChainedAuthFilter</code> is easy, just pass a <code>List<AuthFilter></code> with the filters in the order they should be executed. Dropwizard tries each of the <code>AuthFilter</code>s in turn until one returns successfully.</p>
<p>In the application’s <code>run()</code> method:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17</pre></td><td class="code"><pre><span class="c1">// Application.java</span>
<span class="n">ApiKeyAuthFilter</span> <span class="n">apiKey</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ApiKeyAuthFilter</span><span class="o">.</span><span class="na">Builder</span><span class="o">()</span>
<span class="o">.</span><span class="na">setAuthenticator</span><span class="o">(</span><span class="n">apiKeyAuthenticator</span><span class="o">)</span>
<span class="o">.</span><span class="na">setAuthorizer</span><span class="o">(</span><span class="n">authorizer</span><span class="o">)</span>
<span class="o">.</span><span class="na">setPrefix</span><span class="o">(</span><span class="s">"API key"</span><span class="o">)</span>
<span class="o">.</span><span class="na">buildAuthFilter</span><span class="o">();</span>
<span class="n">DefaultAuthFilter</span> <span class="k">default</span> <span class="o">=</span> <span class="k">new</span> <span class="n">DefaultAuthFilter</span><span class="o">.</span><span class="na">Builder</span><span class="o">()</span>
<span class="o">.</span><span class="na">setAuthenticator</span><span class="o">(</span><span class="n">defaultAuthenticator</span><span class="o">)</span>
<span class="o">.</span><span class="na">setAuthorizer</span><span class="o">(</span><span class="n">authorizer</span><span class="o">)</span>
<span class="o">.</span><span class="na">setPrefix</span><span class="o">(</span><span class="s">"default"</span><span class="o">)</span>
<span class="o">.</span><span class="na">buildAuthFilter</span><span class="o">();</span>
<span class="n">List</span><span class="o"><</span><span class="n">AuthFilter</span><span class="o">></span> <span class="n">filterList</span> <span class="o">=</span> <span class="n">Lists</span><span class="o">.</span><span class="na">newArrayList</span><span class="o">(</span><span class="n">apiKey</span><span class="o">,</span> <span class="k">default</span><span class="o">);</span>
<span class="n">ChainedAuthFilter</span> <span class="n">chainedAuthFilter</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ChainedAuthFilter</span><span class="o"><>(</span><span class="n">filterList</span><span class="o">)</span>
<span class="n">environment</span><span class="o">.</span><span class="na">jersey</span><span class="o">().</span><span class="na">register</span><span class="o">(</span><span class="k">new</span> <span class="n">AuthDynamicFeature</span><span class="o">(</span><span class="n">chainedAuthFilter</span><span class="o">));</span>
<span class="n">environment</span><span class="o">.</span><span class="na">jersey</span><span class="o">().</span><span class="na">register</span><span class="o">(</span><span class="n">RolesAllowedDynamicFeature</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
</pre></td></tr></tbody></table>
</div>
<p>The <code>AuthFilter</code>s and their respective <code>Authenticator</code>s are described below.</p>
<h1>API key authentication</h1>
<p>As mentioned, my user authentication is done with an API key that is passed in the Authorization HTTP header. The filter extracts the value and passes it to the <code>authenticate()</code> method of <code>ApiKeyAuthenticator</code>.</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7</pre></td><td class="code"><pre><span class="c1">// ApiKeyAuthFilter.kt</span>
<span class="n">override</span> <span class="n">fun</span> <span class="nf">filter</span><span class="p">(</span><span class="nl">requestContext:</span> <span class="n">ContainerRequestContext</span><span class="o">)</span> <span class="o">{</span>
<span class="n">val</span> <span class="n">credentials</span> <span class="o">=</span> <span class="n">requestContext</span><span class="o">.</span><span class="na">headers</span><span class="o">.</span><span class="na">getFirst</span><span class="o">(</span><span class="n">HttpHeaders</span><span class="o">.</span><span class="na">AUTHORIZATION</span><span class="o">)</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">authenticate</span><span class="o">(</span><span class="n">requestContext</span><span class="o">,</span> <span class="n">credentials</span><span class="o">,</span> <span class="n">API_KEY_AUTH</span><span class="o">))</span> <span class="o">{</span>
<span class="k">throw</span> <span class="n">WebApplicationException</span><span class="o">(</span><span class="n">unauthHandler</span><span class="o">.</span><span class="na">buildResponse</span><span class="o">(</span><span class="n">prefix</span><span class="o">,</span> <span class="n">realm</span><span class="o">))</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<p>The API key authenticator checks the databse to see if the given API key exists. If the key is found, the matching <code>User</code> is returned; if not found, an empty <code>Optional</code> is returned instead.</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11</pre></td><td class="code"><pre><span class="c1">// ApiKeyAuthenticator.kt</span>
<span class="nd">@Throws</span><span class="o">(</span><span class="nl">AuthenticationException:</span><span class="o">:</span><span class="kd">class</span><span class="err">)</span>
<span class="nc">override</span> <span class="n">fun</span> <span class="n">authenticate</span><span class="o">(</span><span class="nl">credentials:</span> <span class="n">ApiKey</span><span class="o">):</span> <span class="n">Optional</span><span class="o"><</span><span class="n">User</span><span class="o">></span> <span class="o">{</span>
<span class="n">val</span> <span class="n">userId</span> <span class="o">=</span> <span class="n">apiKeyDao</span><span class="o">.</span><span class="na">getUserIdForAccessToken</span><span class="o">(</span><span class="n">credentials</span><span class="o">.</span><span class="na">accessToken</span><span class="o">)</span>
<span class="k">if</span> <span class="o">(</span><span class="n">userId</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="n">val</span> <span class="n">user</span> <span class="o">=</span> <span class="n">userDao</span><span class="o">.</span><span class="na">getUser</span><span class="o">(</span><span class="n">userId</span><span class="o">)</span>
<span class="k">return</span> <span class="n">Optional</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="n">user</span><span class="o">)</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">Optional</span><span class="o">.</span><span class="na">empty</span><span class="o"><</span><span class="n">User</span><span class="o">>()</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<h1>Default authentication</h1>
<p>If API key authentication fails, either because the user provided invalid credentials or no credentials at all, then the next <code>AuthFilter</code> configured in the <code>ChainedAuthFilter</code> is invoked. Authentication for the default user doesn’t actually check anything, so <code>Unit</code> is passed instead of credentials:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6</pre></td><td class="code"><pre><span class="c1">// DefaultAuthFilter.kt</span>
<span class="n">override</span> <span class="n">fun</span> <span class="nf">filter</span><span class="p">(</span><span class="nl">requestContext:</span> <span class="n">ContainerRequestContext</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">authenticate</span><span class="o">(</span><span class="n">requestContext</span><span class="o">,</span> <span class="n">Unit</span><span class="o">,</span> <span class="s">"DEFAULT"</span><span class="o">))</span> <span class="o">{</span>
<span class="k">throw</span> <span class="n">WebApplicationException</span><span class="o">(</span><span class="n">unauthHandler</span><span class="o">.</span><span class="na">buildResponse</span><span class="o">(</span><span class="n">prefix</span><span class="o">,</span> <span class="n">realm</span><span class="o">))</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<p>As the last authenticator to run in the chain, the DefaultAuthenticator never fails, it simply returns a default-constructed <code>User</code> object.</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8</pre></td><td class="code"><pre><span class="c1">// DefaultAuthenticator.kt</span>
<span class="nd">@Throws</span><span class="o">(</span><span class="nl">AuthenticationException:</span><span class="o">:</span><span class="kd">class</span><span class="err">)</span>
<span class="nc">override</span> <span class="n">fun</span> <span class="n">authenticate</span><span class="o">(</span><span class="nl">credentials:</span> <span class="n">Unit</span><span class="o">):</span> <span class="n">Optional</span><span class="o"><</span><span class="n">User</span><span class="o">></span> <span class="o">{</span>
<span class="n">logger</span><span class="o">.</span><span class="na">debug</span><span class="o">(</span><span class="s">"Using default auth"</span><span class="o">);</span>
<span class="n">val</span> <span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="o">()</span>
<span class="k">return</span> <span class="n">Optional</span><span class="o">.</span><span class="na">of</span><span class="o">(</span><span class="n">user</span><span class="o">)</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<h1>Usage in servlets</h1>
<p>The <code>User</code> object looks like this:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16</pre></td><td class="code"><pre><span class="c1">// User.kt</span>
<span class="n">data</span> <span class="kd">class</span> <span class="nf">User</span><span class="p">(</span><span class="n">val</span> <span class="nl">id:</span> <span class="n">Int</span><span class="o">,</span> <span class="nl">roles:</span> <span class="n">List</span><span class="o"><</span><span class="n">Role</span><span class="o">>)</span> <span class="o">:</span> <span class="n">Principal</span> <span class="o">{</span>
<span class="n">constructor</span><span class="o">()</span> <span class="o">:</span> <span class="k">this</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">emptyList</span><span class="o">())</span>
<span class="n">init</span> <span class="o">{</span>
<span class="n">var</span> <span class="n">theRoles</span> <span class="o">=</span> <span class="n">mutableListOf</span><span class="o"><</span><span class="n">Role</span><span class="o">>()</span>
<span class="k">if</span> <span class="o">(</span><span class="n">id</span> <span class="o">!=</span> <span class="mi">0</span><span class="o">)</span> <span class="n">theRoles</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">Role</span><span class="o">.</span><span class="na">USER</span><span class="o">)</span>
<span class="n">roles</span> <span class="o">=</span> <span class="n">theRoles</span><span class="o">.</span><span class="na">toList</span><span class="o">()</span>
<span class="o">}</span>
<span class="n">fun</span> <span class="n">hasRole</span><span class="o">(</span><span class="nl">role:</span> <span class="n">Role</span><span class="o">):</span> <span class="n">Boolean</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">roles</span><span class="o">.</span><span class="na">contains</span><span class="o">(</span><span class="n">role</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<p>Which allows me to check whether valid authentication was provided within a servlet:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10</pre></td><td class="code"><pre><span class="c1">// SomeResource.kt</span>
<span class="n">fun</span> <span class="nf">optionallyAuthenticatedResource</span><span class="p">(</span><span class="nd">@Context</span> <span class="nl">context:</span> <span class="n">SecurityContext</span><span class="o">)</span> <span class="o">{</span>
<span class="n">user</span> <span class="o">=</span> <span class="n">context</span><span class="o">.</span><span class="na">getUserPrincipal</span><span class="o">()</span>
<span class="k">if</span> <span class="o">(</span><span class="n">user</span> <span class="o">!=</span> <span class="kc">null</span> <span class="o">&&</span> <span class="n">user</span><span class="o">.</span><span class="na">hasRole</span><span class="o">(</span><span class="n">Role</span><span class="o">.</span><span class="na">USER</span><span class="o">))</span> <span class="o">{</span>
<span class="c1">// Do something for authenticated users</span>
<span class="o">}</span>
<span class="c1">// Do other stuff for all users</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
Reading Devise Sessions in Javahttp://dinomite.net/blog/2016/05/02/reading-devise-sessions-in-java/2016-05-01T20:00:00-04:002016-05-04T09:45:44-04:00Drew Stephens<p>I have a Ruby on Rails app that uses <a href="https://github.com/plataformatec/devise">Devise</a> for authentication and session management, the latter is really done by <a href="https://github.com/hassox/warden">Warden</a>. We are making a server-side companion for Ruby written in <a href="https://kotlinlang.org/">Kotlin</a> & Java and want to be able to share sessions between the two runtimes.</p>
<p><a href="http://jruby.org/">JRuby</a> makes this easy, allowing you to run Ruby on the JVM. While JRuby supports running entire Ruby applications, for reading sessions we simply want to embed a bit of Ruby within our Java application. This is accomplished by using <a href="https://github.com/jruby/jruby/wiki/RedBridge">JRuby Embed (AKA Red Bridge)</a>.</p>
<p>First, let’s look at the Ruby required to read <a href="http://stackoverflow.com/a/23683925/17339">Warden sessions</a>. Our app stores sessions in a local databae, so we don’t have to deal with encryption or encoding. If your sessions are stored in cookies, they will be encrypted—<a href="http://nipperlabs.com/rails-secretkeybase">this article</a> should give you what you need to decrypt the session.</p>
<div class="highlight ruby"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4</pre></td><td class="code"><pre><span class="n">s</span> <span class="o">=</span> <span class="no">Marshal</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="n">session</span><span class="p">)</span>
<span class="n">csrfToken</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="s1">'_csrf_token'</span><span class="p">]</span>
<span class="n">userId</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="s1">'warden.user.user.key'</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
<span class="n">authenticatableSalt</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="s1">'warden.user.user.key'</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span>
</pre></td></tr></tbody></table>
</div>
<p>The operative part of this is really just one call, <code>Marshal.load(session)</code>. That invokes Ruby’s built-in serializer, <code>Marshal</code>, to deserialize the session string. The subsequent lines just assign variables to make extracting the desired data in Java easier. Here is that script used in context to pull the information into Java:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10</pre></td><td class="code"><pre><span class="kd">public</span> <span class="n">Session</span> <span class="nf">getSession</span><span class="p">(</span><span class="n">String</span> <span class="n">session</span><span class="o">)</span> <span class="o">{</span>
<span class="n">container</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"session"</span><span class="o">,</span> <span class="n">session</span><span class="o">);</span>
<span class="n">container</span><span class="o">.</span><span class="na">runScriptlet</span><span class="o">(</span><span class="n">rubyScript</span><span class="o">);</span>
<span class="kt">int</span> <span class="n">userId</span> <span class="o">=</span> <span class="o">((</span><span class="n">Long</span><span class="o">)</span> <span class="n">container</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"userId"</span><span class="o">)).</span><span class="na">intValue</span><span class="o">();</span>
<span class="n">String</span> <span class="n">authenticatableSalt</span> <span class="o">=</span> <span class="o">((</span><span class="n">String</span><span class="o">)</span> <span class="n">container</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"authenticatableSalt"</span><span class="o">));</span>
<span class="n">String</span> <span class="n">csrfToken</span> <span class="o">=</span> <span class="o">((</span><span class="n">String</span><span class="o">)</span> <span class="n">container</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"csrfToken"</span><span class="o">));</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">Session</span><span class="o">(</span><span class="n">userId</span><span class="o">,</span> <span class="n">authenticatableSalt</span><span class="o">,</span> <span class="n">csrfToken</span><span class="o">);</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<p>The entire Java class looks like this:</p>
<div class="highlight java"><table style="border-spacing: 0"><tbody><tr><td class="gutter gl" style="text-align: right"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35</pre></td><td class="code"><pre><span class="kn">import</span> <span class="nn">org.jruby.embed.LocalContextScope</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.jruby.embed.LocalVariableBehavior</span><span class="o">;</span>
<span class="kn">import</span> <span class="nn">org.jruby.embed.ScriptingContainer</span><span class="o">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SessionReader</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">ScriptingContainer</span> <span class="n">container</span> <span class="o">=</span>
<span class="k">new</span> <span class="n">ScriptingContainer</span><span class="o">(</span><span class="n">LocalContextScope</span><span class="o">.</span><span class="na">CONCURRENT</span><span class="o">,</span>
<span class="n">LocalVariableBehavior</span><span class="o">.</span><span class="na">PERSISTENT</span><span class="o">);</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">script</span> <span class="o">=</span> <span class="s">"s = Marshal.load(session);"</span> <span class="o">+</span>
<span class="s">"csrfToken = s['_csrf_token'];"</span> <span class="o">+</span>
<span class="s">"userId = s['warden.user.user.key'][0][0];"</span> <span class="o">+</span>
<span class="s">"authSalt = s['warden.user.user.key'][1];"</span><span class="o">;</span>
<span class="kd">public</span> <span class="n">Session</span> <span class="n">getSession</span><span class="o">(</span><span class="n">String</span> <span class="n">session</span><span class="o">)</span> <span class="o">{</span>
<span class="n">container</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="s">"session"</span><span class="o">,</span> <span class="n">session</span><span class="o">);</span>
<span class="n">container</span><span class="o">.</span><span class="na">runScriptlet</span><span class="o">(</span><span class="n">script</span><span class="o">);</span>
<span class="kt">int</span> <span class="n">userId</span> <span class="o">=</span> <span class="o">((</span><span class="n">Long</span><span class="o">)</span> <span class="n">container</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"userId"</span><span class="o">)).</span><span class="na">intValue</span><span class="o">();</span>
<span class="n">String</span> <span class="n">authSalt</span> <span class="o">=</span> <span class="o">((</span><span class="n">String</span><span class="o">)</span> <span class="n">container</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"authSalt"</span><span class="o">));</span>
<span class="n">String</span> <span class="n">csrfToken</span> <span class="o">=</span> <span class="o">((</span><span class="n">String</span><span class="o">)</span> <span class="n">container</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"csrfToken"</span><span class="o">));</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">Session</span><span class="o">(</span><span class="n">userId</span><span class="o">,</span> <span class="n">authSalt</span><span class="o">,</span> <span class="n">csrfToken</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="kd">class</span> <span class="nc">Session</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">userId</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">authenticatableSalt</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">csrfToken</span><span class="o">;</span>
<span class="kd">public</span> <span class="n">Session</span><span class="o">(</span><span class="kt">int</span> <span class="n">userId</span><span class="o">,</span> <span class="n">String</span> <span class="n">authenticatableSalt</span><span class="o">,</span> <span class="n">String</span> <span class="n">csrfToken</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">userId</span> <span class="o">=</span> <span class="n">userId</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">authenticatableSalt</span> <span class="o">=</span> <span class="n">authenticatableSalt</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">csrfToken</span> <span class="o">=</span> <span class="n">csrfToken</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></td></tr></tbody></table>
</div>
<p>Using <code>LocalContextScope.CONCURRENT</code> allows this class to be threadsafe. JRuby creates a single runtime and shared variables for the <code>ScriptingContainer</code>, but separate variable mappings for each thread. The other modifier, <code>LocalVariableBehavior.PERSISTENT</code>, keeps the local variables around after we call <code>runScriptlet()</code> allowing for their retrieval back in Java land.</p>
<p>See the <a href="https://github.com/jruby/jruby/wiki/RedBridgeExamples">Red Bridge Examples</a> for more information on using Ruby within Java.</p>