tag:blogger.com,1999:blog-64665451740585735572024-03-08T06:34:00.283-05:00Jerry on JavaThoughts and tips from my experiences in Java EE and web development.Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.comBlogger16125tag:blogger.com,1999:blog-6466545174058573557.post-15900598127613335752015-04-03T20:01:00.000-04:002015-05-11T21:25:02.886-04:005 simple rules for securely storing passwords<p>Far too frequently, systems are hacked and their user databases are compromised. And there are far too many cases where the database contains <a href="http://motherboard.vice.com/blog/hackers-leaked-42-million-plaintext-dating-site-passwords">plain text passwords</a>, <a href="http://arstechnica.com/security/2012/06/8-million-leaked-passwords-connected-to-linkedin/">poorly hashed passwords</a>, or <a href="https://nakedsecurity.sophos.com/2013/11/04/anatomy-of-a-password-disaster-adobes-giant-sized-cryptographic-blunder/">two-way encrypted passwords</a>, despite the wealth of resources available on how to properly store user credentials. And it's not just legacy databases; just this week, I saw a <a href="https://www.reddit.com/r/programming/comments/313cwa/enough_with_the_salts_updates_on_secure_password/">reddit thread</a> with at least one developer advocating custom hashing functions and "security through obscurity".</p>
<p>Though cryptography is a complex subject, you don't need to be an expert to be a good steward of your users' credentials. Just follow these simple rules when selecting a scheme:<a href="#fn1" name="top1"><sup>1</sup></a></p>
<ol>
<li>Use a proven one-way hashing algorithm that has been publicly reviewed by security experts, such as <a href="http://en.wikipedia.org/wiki/Bcrypt">bcrypt</a>, <a href="http://en.wikipedia.org/wiki/PBKDF2">PBKDF2</a>, or <a href="http://en.wikipedia.org/wiki/Scrypt">scrypt</a>.</li>
<li>Don't attempt to write your own hashing algorithm. You can't rely on "security by obscurity"; you must assume the attacker has your source code, and can attack your inferior algorithm.<a href="#fn2" name="top2"><sup>2</sup></a></li>
<li>I mean it, don't write your own hashing algorithm! Just use one of the ones from Rule #1. They are free, available on virtually any platform, and have been proven secure by the best minds in security.</li>
<li>Seriously, why are you even still reading this? Rule #1 is all you need!</li>
<li>Alright, if you are really going to ignore Rule #1, please at least notify your users that you are not safely storing their passwords, and in the event of a database breach, their passwords will become public knowledge.</li>
</ol>
<p>I don't like to deal in absolutes, particularly in software development, but I truly feel strongly about this. <strong>There is no situation in which you should be developing your own password hashing algorithm!</strong><a href="#fn3" name="top3"><sup>3</sup></a> Here's an example of <a href="http://blog.jerryorr.com/2012/05/secure-password-storage-lots-of-donts.html">using PBKDF2 in Java</a> without importing any external libraries; if Node.js is your thing, there's <a href="https://www.npmjs.com/package/bcrypt">a module for bcrypt</a>; there's a <a href="https://github.com/pbhogan/scrypt">Ruby gem for scrypt</a>; hell, even PHP has a <a href="http://php.net/password_hash">built-in password hashing function </a> that uses bcrypt. Really, virtually any language has a freely available library for any of those three algorithms. Just Google "<strong><a href="https://www.google.com/webhp#q=java+bcrypt+or+scrypt+or+pbkdf2">your-language-of-choice bcrypt OR scrypt OR pbkdf2</a></strong>" and you'll find plenty of options.</p>
<p>Any hash function that has not been through rigorous public peer review is almost certainly not properly designed. If <a href="http://en.wikipedia.org/wiki/Niels_Provos">Niels Provos</a> himself — one of the creators of bcrypt — was on my team and wanted to use a new hash function he created in private, I would pass on it and use bcrypt. Although I doubt Mr. Provos would be foolish enough to suggest using such an algorithm; he may have created the next great password hashing algorithm, but he would likely realize that it could not be relied upon until it had been evaluated by his fellow security experts.</p>
<p>So when you need to store user credentials, just please, <em>please</em> hash them with bcrypt, scrypt, or PBKDF2. It's easy. Don't try to be clever.</p>
<hr>
<p class="footnote"><a name="fn1"><sup>1</sup></a> Even better: don't store user credentials if you don't have to. Consider using an OAuth provider, or your organization's internal identity system. It saves some effort, and saves your users from remembering yet another set of credentials.<a href="#top1"><sup>↩</sup></a></p>
<p class="footnote"><a name="fn2"><sup>2</sup></a> This is essentially <a href="http://en.wikipedia.org/wiki/Kerckhoffs%27s_principle">Kerckhoff's principle</a>: "The system must not require secrecy and can be stolen by the enemy without causing trouble"<a href="#top2"><sup>↩</sup></a></p>
<p class="footnote"><a name="fn3"><sup>3</sup></a> Okay, I suppose if you are entering something like the <a href="https://password-hashing.net/">Password Hashing Competition</a> or doing academic research, that's fine. But you still shouldn't be using it in a real application until it has been through thorough public review.<a href="#top3"><sup>↩</sup></a></p>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com2tag:blogger.com,1999:blog-6466545174058573557.post-75229328543023860752015-03-29T21:49:00.000-04:002016-07-22T12:36:41.675-04:00Simplicity<p>Lately, I've been thinking a lot about the importance of simplicity in software. I can remember a time in my career when I considered a single system that does everything to be ideal; I dreamed of building monolithic applications that met every possible need my users may have, and I searched for all-encompassing frameworks that eliminated the need for any other dependencies and abstracted away as many challenges as possible. Why import several small libraries into my application when I could adopt a framework that has everything included?</p>
<p>As time has passed and I've written more software, though, I have come to realize what so many programmers figured out before me: <strong>software works best when it focus on doing one thing well</strong>. And the corollary: <strong>software that tries to do too many things will not excel at all of them.</strong></p>
<p>I've seen this philosophy discussed more often recently, particularly in the backlash to monolithic frameworks like <a href="http://en.wikipedia.org/wiki/JavaServer_Faces">JSF</a> and <a href="http://en.wikipedia.org/wiki/AngularJS">AngularJS</a>; I haven't yet decided if simplicity is gaining popularity, or if I'm just noticing simplicity more now that I better appreciate it. But even if simplicity is gaining traction in software development, it's not a new concept. Dijkstra himself wrote in 1975:</p>
<blockquote>
Simplicity is prerequisite for reliability. <cite>Edsger Dijkstra, <a href="http://www.cs.virginia.edu/~evans/cs655/readings/ewd498.html">How do we tell truths that might hurt?</a></cite></blockquote>
<p>Or consider <a href="http://en.wikipedia.org/wiki/Unix">Unix</a>, around in various forms since the 1960s. Utilities in Unix-like systems (like Linux and Mac OS X) have a tendency to do <strong>one thing only</strong>, but <strong>do it very well.</strong> There are utilities like:</p>
<ul>
<li><code>find</code> - searches a directory structure for files matching an expression</li>
<li><code>xargs</code> - executes an arbitrary command using the output of a previous command as arguments</li>
<li><code>egrep</code> - searches for text matching a given regular expression</li>
<li><code>identify</code> - retrieves image metadata (part of <a href="http://www.imagemagick.org/">ImageMagick</a>)</li>
<li><code>cut</code> - extracts segments of text</li>
<li><code>tar</code> - creates file archives</li>
</ul>
<p>Individually, these are fairly simple programs. They are often useful individually, but they don't do terribly complex things.</p>
<p>But say you want to search through your file system and gather all of your winter holiday season pictures from any year into a single archive? Well, maybe you can find some big monolothic program that will do it for you; you might have to pay for it, it surely does way more than you need, and yet still probably won't do exactly what you want. Or instead, you can compose several simple programs to accomplish your goal:</p>
<code class="block">find . -iname '*.jp*g' -print0 \
| xargs -0 -L 1 -I @ identify -format '%[EXIF:DateTime] %d/%f\n' @ \
| egrep '^[[:digit:]]{4}:12' \
| cut -d' ' -f3- \
| tar -cf december.tar -T -
</code>
<p>This uses <code>find</code> to list all files ending in jpg/jpeg, then <code>xargs</code> to pass each file to <code>identify</code>, which lists the date each image was taken and its name. Then <code>egrep</code> filters the list down to images taken in December of any year, and <code>cut</code> trims the output to just list the December file names. Finally, <code>tar</code> takes that list of files and puts them in an archive. Again, none of these individual tasks was particularly complex; when these simple programs were composed together, though, we were able to do something rather complex.</p>
<p>As a programmer, it's important to understand the difference between writing <strong>complex software</strong> and writing <strong>software that does complex things.</strong> Complex software is difficult to write, difficult to test, and more likely to break. Instead, we should write many pieces of <strong>simple</strong>, <strong>thoroughly tested</strong> software, and compose these simple pieces of software to do complex things.</p>
<p>If you're writing utility libraries, make them as tightly focused as possible, instead of writing some do-it-all super utility belt -- leave those to <a href="http://batman.wikia.com/wiki/Batsuit_%28Nolan_Films%29?file=BaleBelt.jpg">Batman</a>. If you're writing applications, make sure you're writing tight, well-tested modular code; module systems like <a href="http://browserify.org/">Browserify</a> can really help on the client side. Keep it simple.</p>
<p><em>Update: added <code>-print0</code> to <code>find</code> and <code>-0</code> to <code>xargs</code> to properly handle spaces in file names. Thanks <a href="https://www.blogger.com/profile/00882044005568424722">Graingert</a>!</em></p>
<style>
blockquote {
font: 14px/22px normal helvetica, sans-serif;
margin-top: 10px;
margin-bottom: 10px;
margin-left: 50px;
padding-left: 15px;
border-left: 3px solid #ccc;
}
cite {
display: block;
}
cite:before {
content: "- ";
}
code {
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
background-color: #f9f2f4;
border-radius: 4px;
white-space: pre;
font-style: normal;
}
code.block {
display: inline-block;
width: 100%;
}
</style>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com5tag:blogger.com,1999:blog-6466545174058573557.post-9775758458484873662014-09-30T20:10:00.000-04:002015-05-11T21:24:34.474-04:00Response from Rep. Scott Perry (R-PA) on Net Neutrality<p>I contacted <a href="http://perry.house.gov/">Scott Perry (R-PA)</a>, my U.S. Congressman, to encourage him to support <a href="http://www.savetheinternet.com/net-neutrality-resources">net neutrality</a>. <a href="http://blog.jerryorr.com/2014/09/response-from-sen-pat-toomey-r-pa-on.html">Like Pat Toomey (R-PA)</a>, my U.S. Senator, he opposes it:</p>
<blockquote style="background-color: #F5F5F5; padding: 10px">
<p>Thank you for contacting me regarding the Federal Communications Commission's (FCC) newly proposed net neutrality rules. I appreciate learning your views on this issue.</p>
<p>I'm committed to doing everything possible to ensure a transparent, accountable, and openly available Internet. In the last year, I voted for Representative Justin Amash's amendment to end NSA mass surveillance (H.Amdt. 413) and supported the Digital Accountability and Transparency (DATA) Act (H.R. 2061), which requires information on all federal spending to be posted to a comprehensive and searchable website.</p>
<p>As you know, earlier this year the U.S. Court of Appeals for the District of Columbia struck down portions of the FCC's 2010 Open Internet Order, ruling that the agency's rules overstepped its regulatory authority under current law. As a result, FCC Chairman Tom Wheeler proposed a new set of net neutrality rules on May 15, 2014. While these rules are not finalized, the FCC is encouraging interested individuals and groups to comment on the proposal, either through the FCC website or by sending an e-mail to openinternet@fcc.gov.</p>
<p>Know that I support a hands-off approach to the Internet. Since the Telecommunications Act of 1996 was passed, new technologies and advancements in telecommunications have rapidly developed due to the limited government regulation of Internet traffic and services. According to the FCC National Broadband Plan, this unrestricted free market has provided broadband to over 95% of Americans without government intervention or interference. Please know that I will continue to support policies that preserve the Internet's open structure to promote innovation, spur economic growth, and protect the free exchange of ideas.</p>
<p>Once again, thank you for contacting me. I appreciate your concerns and welcome your continued feedback. Please visit my website at perry.house.gov to submit further questions/comments or to sign up for my e-newsletter, Facebook page, and/or Twitter updates.</p>
<p>Scott Perry<br>
Member of Congress</p>
</blockquote>
It was rather difficult find Rep. Perry's position on net neutrality. I couldn't find any news articles or press releases, and I never received a response to my emails, tweets, or Facebook messages. I finally called his Washington D.C. office; I spoke with a very polite and helpful staffer, and they sent me the email above.
<p>Whatever your position is on net neutrality, if you are a U.S. citizen, I encourage you to <a href="http://www.opencongress.org/people/zipcodelookup">contact your senators and representatives</a> and let them know where you stand. We may not all have the financial resources to compete with large telecoms, but we do still have the votes.</p>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com0tag:blogger.com,1999:blog-6466545174058573557.post-13070481673946184452014-09-28T20:44:00.001-04:002015-05-11T21:24:47.428-04:00New programming techniques and the productivity curve<p>Though I love learning new programming techniques and technologies, I often struggle to make them a part of my normal development processes. For example, it took years before I finally started using <a href="https://en.wikipedia.org/wiki/Regular_expression">regular expressions</a> on a normal basis. The reason? The productivity curve:</p>
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_eRxNNnpTyr3f4QuDAT2F4faHUCBYzrIDNf3kyBpdVyGrH4rJDGadpEHIO7tdMvk-UL9qVJWCHQ7fDDXdykAEQLHNvz24xM0YVCg3SwWdTlYO5wSCAhAabLkyOMkjswPy0ny4G2R-wg/s1600/Productivity+Curve.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_eRxNNnpTyr3f4QuDAT2F4faHUCBYzrIDNf3kyBpdVyGrH4rJDGadpEHIO7tdMvk-UL9qVJWCHQ7fDDXdykAEQLHNvz24xM0YVCg3SwWdTlYO5wSCAhAabLkyOMkjswPy0ny4G2R-wg/s1600/Productivity+Curve.png" /></a></div>
<p>You may have seen a chart like this before; the productivity curve is used to show one of the <a href="http://msdn.microsoft.com/en-us/library/bb833026.aspx">challenges of software delivery</a>. The general idea is that when you first use a new product (or technology), your productivity always plummets in the short term. No matter how much better the new stuff is, <strong>you will be less productive using it at first</strong>, because you were more familiar with the old stuff. However, as you become more proficient with the new technology, your productivity gradually increases, and eventually your productivity will be greater than it was with the old technology (assuming the new technology is actually better).</p>
<p>So the key is to push through that initial dip, and eventually you get to the increased productivity that comes with mastering the new technology. Easy, right? Well, if your company just replaced your HR system, you have little choice in the matter; you’ll get through that productivity dip because you have no other choice. </p>
<p>However, if you’ve just decided you want to pick up a new programming technique, it’s a little more difficult. Before I got the hang of regular expressions, it was simply far faster for me to whip together something ugly using things like <a href="http://docs.oracle.com/javase/7/docs/api/java/util/StringTokenizer.html">StringTokenizers</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring">substring</a>. Nobody cared if I was using regular expressions, but they did care if I took 10 times as long to complete a task.</p>
<p>On the rare occasions where I needed to make a change to existing regular expressions, I’d end up slogging through references and online tutorials to try and make sense out of it. Each time, after finally figuring it out, I’d tell myself that I was going to remember how these worked next time. But since I hadn’t made regular expressions a part of my standard toolchain, I’d forget everything I learned, and I would be lost again next time I needed to use them.</p>
<p>I eventually got the hang of regular expressions through <strong>forced practice</strong> and <strong>forced application</strong>. </p>
<p><strong>Forced practice</strong> was straightforward enough: I dedicated time to reading <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">references</a>, running through <a href="http://regexone.com/">tutorials</a>, and solving <a href="http://callumacrae.github.io/regex-tuesday/">regex challenges</a>. This practice was an important step in building the skills, but I had tried this to a certain degree before. I’d spend a few hours practicing regular expressions, and feel like I was getting the hang of it. But time would pass, and the next time I needed to fix a regex, I’d have forgotten most of it again.</p>
<p>The key for me was <strong>forced application</strong> of regular expressions. Like the poor HR staff who learn a new HR system because they have no other choice, I forced myself to use regular expressions any time they could be useful, <strong>even though it would take me longer</strong> than a quick hack with stuff I was already familiar with. Good unit tests helped a lot; though I was not confident in my ability to write bug-free regular expressions, I was confident in my ability to write thorough tests. </p>
<div style="float: right; margin: 0px 0px 10px 10px;"><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- Article inline -->
<ins class="adsbygoogle"
style="display:inline-block;width:300px;height:250px"
data-ad-client="ca-pub-4657506819321826"
data-ad-slot="3700917392"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></div>
<p>As the productivity curve predicted, I was definitely less efficient at first. But as I forced myself to use regular expressions instead of hacking something together more quickly, I gradually improved. And before long, I was past the productivity dip, having finally gotten the hang of regular expressions. Now they are an essential part of my development toolchain, and I am a better programmer.</p>
<p>I know this isn’t really earth shattering advice; my five year old son has figured out that you get better at something the more you do it. But when you find some new technology or technique you want to make part of your development process, I think it’s important to go into it recognizing that not only will it take time to master it, but <strong>you will almost certainly be less productive in the short-term than you were before</strong>. And I think that if you are prepared for the productivity dip and <strong>are willing to accept it</strong>, you can push through the difficult times and master it. In the long run, you will be a better developer for it.</p>
<div style="text-align: middle">
<a href="https://twitter.com/JerryOnJava" class="twitter-follow-button" data-show-count="false" style="text-align: middle; margin-left: auto; margin-right: auto">Follow @JerryOnJava</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
<script charset="utf-8" src="http://widgets.twimg.com/j/2/widget.js"></script>
<script>
new TWTR.Widget({
version: 2,
type: 'profile',
rpp: 5,
interval: 30000,
width: 250,
height: 300,
theme: {
shell: {
background: '#333333',
color: '#ffffff'
},
tweets: {
background: '#000000',
color: '#ffffff',
links: '#4aed05'
}
},
features: {
scrollbar: false,
loop: false,
live: false,
behavior: 'all'
}
}).render().setUser('JerryOnJava').start();
</script>
</div>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com1tag:blogger.com,1999:blog-6466545174058573557.post-72784077711470625662014-09-15T14:46:00.000-04:002015-05-11T21:24:53.587-04:00Response from Sen. Pat Toomey (R-PA) on Net Neutrality<p>I emailed <a href="http://www.toomey.senate.gov/">Pat Toomey (R-PA)</a>, my U.S. Senator, to encourage him to support <a href="http://www.savetheinternet.com/net-neutrality-resources">net neutrality</a>. As you can see from his response, he is opposed to it:</p>
<blockquote style="background-color: #F5F5F5; padding: 10px">
<p>Thank you for contacting me about Federal Communications Commissions' (FCC) net neutrality regulation. I appreciate knowing your thoughts on this issue.</p>
<p>As you may know, on December 21, 2010, the FCC adopted an Open Internet Order, better known as "net neutrality," that imposed new federal regulations on the types of services Internet providers could sell. Verizon Communications sued the FCC arguing that the regulations were too stringent and went beyond the agency's authority.</p>
<p>On January 14, 2014, in the case Verizon Communications Inc. v. FCC, the D.C. Circuit Court of Appeals struck down the FCC's net neutrality regulation. The Court stated that the FCC did not have the statuary authority to compel a broadband provider to follow the Open Internet Order.</p>
<p>I understand the concerns expressed by those who support net neutrality regulations; however, I also believe that such federal mandates would unduly inhibit this industry's innovation, investment in new technology, and job creation. Moreover, the Internet and online content have thrived in the United States without net neutrality regulations, which throws into question the need for more government intervention. Although there is currently no legislation before the Senate addressing net neutrality, please be assured that I will keep your thoughts on net neutrality in mind, should the Senate begin consideration of open internet legislation.</p>
<p>Thank you again for your correspondence. Please do not hesitate to contact me in the future if I can be of assistance.</p>
<p>Sincerely,</p>
<p>Pat Toomey<br/>
U.S. Senator, Pennsylvania</p>
</blockquote>
Whatever your position is on net neutrality, if you are a U.S. citizen, I encourage you to <a href="http://www.opencongress.org/people/zipcodelookup">contact your senators and representatives</a> and let them know where you stand. We may not all have the financial resources to compete with large telecoms, but we do still have the votes.Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com0tag:blogger.com,1999:blog-6466545174058573557.post-17412207711290525922014-08-27T13:23:00.000-04:002015-05-11T21:25:23.345-04:00Yes, you CAN unit test client side code (video)<p>When developers think about unit testing web applications, we often focus on server-side code. We may think that testing client-side code (JavaScript, HTML, CSS) either can’t be done or is limited to isolated scenarios. But with the right tools and programming techniques, we can achieve the same rigorous test quality in our client code that we expect from our server code.</p>
<p>In this <a href="http://webconference.psu.edu/">Web Conference at Penn State</a> presentation, I demonstrated how to use tools like <a href="http://visionmedia.github.io/mocha/">Mocha</a> and <a href="http://phantomjs.org/">PhantomJS</a> to build rigorous client tests. I also discussed programming techniques to make client code more easily testable.</p>
<p>All sample code is <a href="https://github.com/jerryorr/client-testing">available on GitHub</a>.</p>
<iframe width="811" height="484" src="//www.youtube.com/embed/oIEoSym82os" frameborder="0" allowfullscreen></iframe>
<p><a class="twitter-follow-button" data-show-count="false" href="https://twitter.com/JerryOnJava">Follow @JerryOnJava</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script></p>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com0tag:blogger.com,1999:blog-6466545174058573557.post-59625175474347151962014-04-15T20:47:00.000-04:002015-05-11T21:26:18.527-04:00Solve your problem by almost asking a question on StackOverflowIf you were to look at my <a href="http://stackoverflow.com/" target="_blank">StackOverflow</a> profile, you would see that I’ve only asked a handful of questions in the years that I’ve been a member. However, this is <i>not</i> because I don’t run into programming problems or don’t think to ask questions. In the process of formulating a <a href="http://stackoverflow.com/help/how-to-ask" target="_blank">good StackOverflow question</a>, I usually find the answer myself.<br />
<br />
First of all, it’s embarrassing to spend time typing up a question and have someone respond with a Google search providing dozens of hits that provide the answer. So before I even start typing, you’d better believe I <b>Google the hell out of the problem.</b> And many times, I find what I'm looking for.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJCtCErj7q3SWxpBXhQ3WvFS-dXZFil-teJZ_IlAegbfc5tWfXg6TAtdnq22nBqyeVTFsxVLZEqBXs0d11zUD0a28yD4DI-Yae2W4wBmKzK6lnSBvkCEXFZFqvO6ZH1Dp-sFpa0NcaRQ/s1600/help-me-help-you-gif.gif" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJCtCErj7q3SWxpBXhQ3WvFS-dXZFil-teJZ_IlAegbfc5tWfXg6TAtdnq22nBqyeVTFsxVLZEqBXs0d11zUD0a28yD4DI-Yae2W4wBmKzK6lnSBvkCEXFZFqvO6ZH1Dp-sFpa0NcaRQ/s1600/help-me-help-you-gif.gif" /></a></div>
Assuming Google fails me, now I start explaining my problem. Since my audience is a group of complete strangers that have no knowledge of my application, I can’t simply say “I’m getting a SplinesNotReticulatedException from my FlangerFactory.” Even if I happen to be working on an open source project, I can’t expect the StackOverflow community to take the time to understand my full code base in depth. Thus, I am forced to <b>write a small example demonstrating the problem</b>. This is a fantastic way to narrow down the problem, because if I think the problem is with Dojo, but I can’t write a small example outside of my code base to reproduce the problem, then I’m most likely not dealing with a Dojo bug. In fact, there’s a good chance I’m looking in the wrong area of my code base. And if I can reproduce the problem, then maybe I can file a bug report with Dojo.<br />
<br />
Now I have a simple code example that helpful members of the community can work from. So that they don’t waste their time running into the same walls I did, I <b>explain exactly what I’ve tried thus far that hasn’t worked</b>. This saves a lot of back-and-forth “nope, I tried that and it doesn’t work” comments. And in the process of documenting what I’ve already tried, I often come up with new ideas. And sometimes, one of those ideas actually solves the problem.<br />
<br />
Of course, while I used StackOverflow as an example, this process really works with any community and medium, including emailing my coworkers. I respect the time of those who help me, so I make every effort to ask for help in the most efficient manner possible. In every forum I use, I always follow this process:<br />
<br />
<ol>
<li>Thoroughly search Google (and any other available non-human resources).</li>
<li>Write a concise example demonstrating the problem.</li>
<li>Explain any failed attempts to solve the problem.</li>
</ol>
<br />
More often than not, I solve the problem myself by going through this process. And if I don’t discover the solution myself, then I have constructed a proper question that gives me the best chance of getting the help I need from my community.
<br />
<br />
<b>Update: </b>as several Redditers <a href="http://www.reddit.com/r/programming/comments/237518/solve_your_problem_by_almost_asking_a_question_on/" target="_blank">have pointed out</a>, if you've documented a problem and found a solution, you should share it! StackOverflow <a href="http://stackoverflow.com/help/self-answer" target="_blank">actually encourages posting and immediately answering your own question</a>, and I imagine most communities feel the same way. My focus in this post was on discussing how to properly research and document a problem before asking for help, and highlighting how often you could end up solving the problem yourself, but I left out the importance of sharing that information with others.<br />
<br />
I wouldn't necessarily recommend posting your solution if it's "oops, I found a missing comma in one of my modules", and I don't think we need any more StackOverflow questions that could easily be solved via a Google search (that probably points back to a dozen StackOverflow questions). But if your solution could actually help others, then go ahead and publish it in whatever forum you like, or put it up on your personal blog, or email it to your coworkers...<br />
<br />
<a class="twitter-follow-button" data-show-count="false" href="https://twitter.com/JerryOnJava">Follow @JerryOnJava</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com4tag:blogger.com,1999:blog-6466545174058573557.post-79949554950434804612013-10-31T09:54:00.000-04:002015-05-11T21:26:33.802-04:00Using Node.js streams to massage data into the format you wantGoogle provides some pretty cool flu data in <a href="http://www.google.org/flutrends/us/data.txt" target="_blank">CSV format</a>, and I wanted to display that in a chart at <a href="https://www.thedash.com/" target="_blank">Dash</a>. However, the raw data isn't quite right for my needs:<br />
<ol>
<li>It has a bunch of intro/header text (copyright stuff, description of the data, etc), and Dash needs just the raw data.</li>
<li>It shows dozens of states/regions/cities, and I just want to show overall U.S. data and my home state.</li>
</ol>
<div>
Fortunately, Dash can read data from any publicly accessible endpoint, so I decided to throw together a quick <a href="http://nodejs.org/" target="_blank">Node.js</a> app to massage the data into what I needed. The most straightforward solution was probably to load the whole file, read through it line by line, build up an array of data, then write it out. And since the data feed is currently just under 400KB, maybe that would have been alright. But a better pattern (and more fun, IMO) is to take advantage of Node Streams. As long as we use streams throughout the entire process, we can make sure that only a small buffer is kept in memory at any given time.<br />
<br />
If you just want to see the full app, <a href="https://github.com/jerryorr/sniffles" target="_blank">it's on GitHub</a>. Otherwise, read on to see my thought process.<br />
<br /></div>
<div>
<h3>
Filter out the intro/header text</h3>
</div>
<div>
First, we'll write a stream that filters out the copyright/overview stuff and passes on the rest:<br />
<br /></div>
<div>
<pre class="brush: js">var stream = require('stream')
, util = require('util')
function CleanIntro(options) {
stream.Transform.call(this, options)
}
util.inherits(CleanIntro, stream.Transform)
CleanIntro.prototype._transform = function (chunk, enc, cb) {
if (this.readingData) {
this.push(chunk, enc)
} else {
// Ignore all text until we find a line beginning with 'Date,''
var start = chunk.toString().search(/^Date,/m)
if (start !== -1) {
this.readingData = true
this.push(chunk.slice(start), enc)
}
}
cb()
}
</pre>
</div>
<div>
<br />
A Transform stream simply takes data that was piped in from another stream, does whatever it wants to it, then pushes whatever it wants back out. In our case, we're just ignoring anything before the actual data begins, then pushing the rest of the data back out. Easy.<br />
<br />
<h3>
Parse the CSV data</h3>
</div>
<div>
Now that we have a filter to get just the raw CSV data, we can start parsing it. There are lots of CSV parsing libraries out there; I like <a href="https://npmjs.org/package/csv-stream" target="_blank">csv-stream</a> because, well, it's a stream. So our basic process is to make the HTTP request, pipe it to our header-cleaning filter, then pipe it to csv-stream and start working with the data:</div>
<div>
<pre class="brush: js">var request = require('request')
, csv = require('csv-stream')
, util = require('util')
, _ = require('lodash')
, moment = require('moment')
, OutStream = require('./out-stream')
, CleanIntroFilter = require('./clean-intro-filter')
// Returns a Stream that emits CSV records from Google Flu Trends.
// options:
// - regions: an array of regions for which data should be generated.
// See http://www.google.org/flutrends/us/data.txt for possible values
module.exports = function (options) {
options = _.extend({
regions: ['United States']
}, options)
var earliest = moment().subtract('years', 1)
request('http://www.google.org/flutrends/us/data.txt')
.pipe(new CleanIntroFilter())
.pipe(csv.createStream({}))
.on('error',function(err){
// Oops, got an error
})
.on('data',function(data) {
var date = moment(data.Date)
// Only return data from the past year
if (date.isAfter(earliest) || date.isSame(earliest)) {
// Let's build the output String...
console.log(data.Date + ',' + _.map(options.regions, function (region) {
return data[region]
}).join())
}
})
.on('end', function () {
// Okay we're done, now what?
})
}
</pre>
<br /></div>
<div>
Alright, now we're getting close. We've built the CSV output, but now what do we do with it? Push it all into an array and return that? <b>NO!</b> Remember, we'll lose the slim memory benefits of streams if we don't keep using them the whole way through.<br />
<br />
<h3>
Write out to another Stream</h3>
</div>
<div>
Instead, let's just make our own writeable stream:</div>
<div>
<pre class="brush: js">var stream = require('stream')
var OutStream = function() {
stream.Transform.call(this,{objectMode: false})
}
OutStream.prototype = Object.create(
stream.Transform.prototype, {constructor: {value: OutStream}} )
OutStream.prototype._transform = function(chunk, encoding, callback) {
this.push(chunk, encoding)
callback && callback()
}
OutStream.prototype.write = function () {
this._transform.apply(this, arguments)
}
OutStream.prototype.end = function () {
this._transform.apply(this, arguments)
this.emit('end')
}
</pre>
<br /></div>
<div>
And now our parsing function can return that stream and write to it:
<br />
<pre class="brush: js">module.exports = function (options) {
options = _.extend({
regions: ['United States']
}, options)
var out = new OutStream()
out.write('Date,' + options.regions.join())
var earliest = moment().subtract('years', 1)
request('http://www.google.org/flutrends/us/data.txt')
.pipe(new CleanIntroFilter())
.pipe(csv.createStream({}))
.on('error',function(err){
out.emit('error', err)
})
.on('data',function(data) {
var date = moment(data.Date)
// Only return data from the past year
if (date.isAfter(earliest) || date.isSame(earliest)) {
out.write(data.Date + ',' + _.map(options.regions, function (region) {
return data[region]
}).join())
}
})
.on('end', function () {
out.end()
})
return out
}
</pre>
<br />
<h3>
Serve it up</h3>
</div>
<div>
Finally, we'll use <a href="http://expressjs.com/" target="_blank">Express</a> to expose our data as a web endpoint:</div>
<div>
<pre class="brush: js">var express = require('express')
, data = require('./lib/data')
, _ = require('lodash')
var app = express()
app.get('/', function(req, res){
var options = {}
if (req.query.region) {
options.regions = _.isArray(req.query.region) ? req.query.region : [req.query.region]
}
res.setHeader('Content-Type', 'text/csv')
data(options)
.on('data', function (data) {
res.write(data)
res.write('\n')
})
.on('end', function (data) {
res.end()
})
.on('error', function (err) {
console.log('error: ', error)
})
})
var port = process.env.PORT || 5000
app.listen(port)
console.log('Listening on port ' + port)</pre>
<br />
Once again, note that as soon as we get data from our stream, we manipulate and write it out to another stream (the HTTP response, in this case). This keeps us from holding a lot of data in memory unnecessarily.<br />
<br />
Now if we fire up the server, we can use curl to see it in action:<br />
<br />
<pre class="brush: text">$ curl 'http://localhost:5000'
Date,United States
2012-11-04,2492
2012-11-11,2913
2012-11-18,3040
2012-11-25,3641
2012-12-02,4427
[and so on]
$ curl 'http://localhost:5000?region=United%20States&region=Pennsylvania'
Date,United States,Pennsylvania
2012-11-04,2492,2579
2012-11-11,2913,2889
2012-11-18,3040,2785
2012-11-25,3641,3248
2012-12-02,4427,3679
[and so on]
</pre>
<br />
As long the server is running someplace that is accessible to the public, we can head on over to <a href="http://thedash.com/" target="_blank">Dash</a> and plug it into a Custom Chart widget, giving us something like this:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4KXUHBfx5wGsZY_2BlQxUI16UoNbFawEP4XO_hi7K1L8hm3DvE8QRLtHES41OPtEwO2u8hTDr70TBt2Yz9rv3CvvKBO18nXyD_gcEP1uLiRqFA0_-lBuNn3ZjrUverCqKK0-yvanYUA/s1600/flu+chart+in+Dash.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="264" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4KXUHBfx5wGsZY_2BlQxUI16UoNbFawEP4XO_hi7K1L8hm3DvE8QRLtHES41OPtEwO2u8hTDr70TBt2Yz9rv3CvvKBO18nXyD_gcEP1uLiRqFA0_-lBuNn3ZjrUverCqKK0-yvanYUA/s640/flu+chart+in+Dash.png" width="640" /></a></div>
Hey, looks like December and January are big months for the flu in the U.S. Who knew?<br />
<br />
Want to try this yourself? The full source for this app <a href="https://github.com/jerryorr/sniffles" target="_blank">is on GitHub</a>, along with step-by-step instructions for running the project and creating a widget in Dash. Enjoy!<br />
<br /></div>
<link href="//cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/styles/shCore.min.css" rel="stylesheet" type="text/css"></link> <link href="//cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/styles/shThemeRDark.min.css" rel="stylesheet" type="text/css"></link> <script src="//cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/scripts/shCore.min.js" type="text/javascript">
</script> <script src="//cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/scripts/shBrushJScript.min.js" type="text/javascript">
</script> <script src="//cdnjs.cloudflare.com/ajax/libs/SyntaxHighlighter/3.0.83/scripts/shBrushPlain.min.js" type="text/javascript">
</script><script type="text/javascript">
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.defaults['toolbar'] = true;
SyntaxHighlighter.defaults.gutter = false;
SyntaxHighlighter.all();
</script>
<style>div.syntaxhighlighter { padding: 5px; }</style>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com21tag:blogger.com,1999:blog-6466545174058573557.post-27610643888572141912013-10-16T11:26:00.002-04:002013-10-16T11:26:28.203-04:00Cut the HealthCare.gov people some slackOn October 1, 2013, <a href="http://healthcare.gov/" target="_blank">HealthCare.gov</a> was opened to the nation. As one of the more tangible aspects of the Affordable Care Act (aka ACA, Obamacare), the glitches it has experienced are getting lots of negative attention. It's been described as an "<a href="http://www.usatoday.com/story/opinion/2013/10/07/health-care-insurance-exchanges-obamacare-editorials-debates/2940207/" target="_blank">inexcusable mess</a>" and a "<a href="http://www.businessinsider.com/frustrated-with-the-new-health-care-exchange-2013-10" target="_blank">disaster</a>". I'm not going to discuss the merits of the ACA here. But as someone who spends every day building software, I think the criticisms of the HealthCare.gov application have been unfair. Here are a few reasons why we should cut them some slack.<br />
<br />
<h3>
Most webapps aren't immediately released to millions of users</h3>
<div>
When Google or Facebook are releasing a new app, do you think they just flip a switch and release it to the world? Absolutely not! They slowly release it to beta testers, or add the feature to a subset of users. They encounter bugs, fix them, slowly scale up their infrastructure, and wait until they've seen it succeed before opening it up to the general public.</div>
<div>
<br /></div>
<div>
HealthCare.gov, on the other hand, launched to the entire nation at once. It didn't just have to deal with traffic from thousands (hundreds of thousands? millions?) of people looking for health plans for themselves; I'm sure a lot of curious people (like myself) went there <a href="http://www.cnn.com/2013/10/15/health/obamacare-signup-issues-cohen/" target="_blank">just to check it out</a>. There was no chance to work out the bugs, and no chance to gradually scale the infrastructure. This was almost guaranteed to be a problem.</div>
<div>
<br /></div>
<div>
Now, perhaps they <i style="font-weight: bold;">should</i> have slowly rolled out the site. I suspect, however, that the reasons were political. How do you decide who gets to sign up for healthcare first? By state? By last name? Random drawing? People who signed up ahead of time? And how do you explain to everyone else that they have to wait? People expect this from Google, but a highly charged political issue like the ACA makes it dicey.</div>
<div>
<br /></div>
<h3>
Much of what happens in the exchange is out of their control</h3>
<div>
HealthCare.gov is an extremely distributed application. John McDonough, a health policy professor at the Harvard School of Public Health, described it as:</div>
<blockquote class="tr_bq">
"an enormously complex task. The number of systems that have to work together – federal, state, insurance companies, the Internal Revenue System – the number of systems that have to align here is pretty daunting."</blockquote>
If there's a bug in the IRS endpoints, there's going to be a problem. If one of the hundreds of private insurance companies' systems can't handle the increased workload, there's going to be a problem. And as someone who has built plenty of distributed systems, I know that end users don't say "oh, it must be a problem with system X that this app depends on". They think it's a problem with whatever webapp they're using, and don't care what's going on in the backend.<br />
<br />
Nor should they care. But professional IT people should know better.<br />
<br />
<h3>
Most webapps aren't serving as a referendum on a heated national controversy</h3>
<div>
Frankly, there are a lot of people that want HealthCare.gov to fail primarily because they want the ACA to fail. And many people who oppose the ACA will still have a need to use HealthCare.gov. New Google apps are not typically tied to such a heated political issue, and are generally not used by people who don't want to use them. </div>
<div>
<br /></div>
<h3>
So let's have some empathy for the people who build HealthCare.gov</h3>
<div>
This application was an enormous undertaking, with many challenges that few (if any) systems out there need to deal with. My expectation and hope is that the bugs will be worked out in the coming weeks, as happens with any new system. Whether the Affordable Care Act will be a success is yet to be seen; but the healthcare exchanges that support it were built by regular IT professionals that are just trying to do their jobs. Let's cut them some slack.</div>
Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com11tag:blogger.com,1999:blog-6466545174058573557.post-47996423513747912602013-03-07T13:52:00.003-05:002015-05-11T21:26:52.001-04:00A case for putting off documentation until the endI have a bad habit of putting off documenting my code as long as possible; it's often my last task before I submit a pull request. And every time I'm slogging through hundreds or thousands of lines of code writing documentation, I think "Next time, I'm going to do this as I go along." And the next time I write a new feature, I'll probably leave the documentation until the end again.<br />
<br />
As bad as this is, though, I've realized there are a few advantages to waiting until your code is finished before writing the documentation:<br />
<div>
<ol>
<li><b>Minimize wasted effort: </b>In an ideal world, your API and requirements wouldn't change after you've started coding. But how often does that happen? If you need to change your code and you've already documented it, now you have to waste time updating your documentation.</li>
<li><b>Forced self-review: </b>Have you ever written a section of code, then looked at it later and realized you could have done it better? While going back through your code to document it, you are forced to reevaluate everything you've done; the extra time between coding and documenting can sometimes give you the perspective you need to refactor it.</li>
<li><b>Catch dead code:</b> Nothing makes me want to delete unnecessary code more than having to document it. Before I document a method, I'll probably check to make sure it's actually still being used.</li>
<li><b>Consistency: </b>I find I used more consistent terminology in my documentation when I'm doing it all at once. I get in a zone, find a language I think works, and stick with it the whole way through.</li>
</ol>
<div>
Of course, there are some reasons nobody actually encourages this behavior:</div>
</div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="http://www.forafewmoviesmore.com/wp-content/uploads/2012/09/frodo-sam-emyn-muil.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="135" src="http://www.forafewmoviesmore.com/wp-content/uploads/2012/09/frodo-sam-emyn-muil.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">One class documented... many more to go...</td></tr>
</tbody></table>
<div>
<ol>
<li><b>It's awful: </b>If you don't enjoy documentation (and I definitely do not), it is <i style="font-weight: bold;">really</i> painful to write it all at once. Writing the documentation every time you write a method is annoying; writing documentation for dozens of methods is brutal.</li>
<li><b>Faded memory: </b>By the time you finally write the documentation, you may have forgotten what the code does or why you made certain decisions. On the flip side, this is a good indication that you should refactor your code anyway.</li>
<li><b>Eh, forget it: </b>When faced with this monumental task, it will be very tempting to just skip the documentation, or put it on your TODO list for later. Sometimes you may be <i>able</i> to get away with this, but you really never <i>should</i>.</li>
</ol>
<div>
So I guess I'm not exactly <i>recommending</i> that you wait until the last minute to write your documentation. I'm just saying that there are some upsides to it. Or maybe I'm really just trying to justify my own behavior...</div>
<div>
<br /></div>
</div>
Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com0tag:blogger.com,1999:blog-6466545174058573557.post-41397388850921047762012-08-02T21:47:00.000-04:002015-05-11T21:27:09.113-04:00A petition to release government-developed software to the OSS communityIn July 2012, <a href="https://petitions.whitehouse.gov/petition/maximize-public-benefit-federal-technology-sharing-government-developed-software-under-open-source/6n5ZBBwf" target="_blank">a petition was created</a> to mandate that U.S. federal government-developed software be released to the open source community. I think this is a fantastic idea, and I'd like to elaborate on some of the points made in the petition (highlighting is mine):<br />
<blockquote class="tr_bq" style="background-color: #eeeeee; font-style: italic; padding: 8px;">
Openness: Open Sourcing ensures basic fairness and transparency by making software and related artifacts available to the <b>citizens who provided funding</b>, consistent with the President’s 2009 declaration that “Information maintained by the Federal Government is a national asset.”</blockquote>
If you pay taxes in the United States, then you are paying for the software developed by the government; taxpayers can reap maximum value for their investment by releasing that software to the open source community.<br />
<br />
There's even a logical precedent for this; a "work of the United States government" <a href="http://en.wikipedia.org/wiki/Copyright_status_of_work_by_the_U.S._government" target="_blank">is not entitled to copyright protection</a> (essentially public domain). An excellent example is photos taken by the federal government, which are public domain and <a href="http://www.dotgovwatch.com/?/archives/8-The-Best-Copyright-Free-Photo-Libraries.html" target="_blank">freely available</a>.<br />
<blockquote class="tr_bq" style="background-color: #eeeeee; font-style: italic; padding: 8px;">
Supports the Federal “Shared First” Agenda: Maximizes value to the government by significantly increasing reuse and <b>collaborative development between federal agencies and the private sector</b>...</blockquote>
I think this collaboration could result in a few interesting scenarios:<br />
<br />
<ul>
<li>Software developed by the government (which costs taxpayers a significant sum of money) could be leveraged by private sector developers, just as software developed by the private sector and then open sourced has driven so many fantastic projects. In fact, the National Security Agency has already given their <a href="https://accumulo.apache.org/" target="_blank">Accumulo</a> NoSQL database to Apache.</li>
<li>Private sector developers could actually <i>improve</i> the software the government has developed! Imagine what some of those sharp <a href="http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CFkQFjAA&url=http%3A%2F%2Fcode.google.com%2Fsoc%2F&ei=PSkbUOKgMaa36wHjs4DgBA&usg=AFQjCNHYqgEvTO1C4hLHRJeRalIWun65TQ" target="_blank">Google Summer of Code</a> developers could do for a summer project! That sounds to me like democracy for the 21st century.</li>
<li>Open sourcing the <i>software </i>could be an important bridge to opening up the wealth <i>data</i> our government collects. Obviously there would be privacy and security concerns, but far more data would be released if private sector developers were contributing new APIs to open sourced government software.</li>
</ul>
<br />
<h2>
What you can do</h2>
<div>
The easiest thing you can do is <a href="https://petitions.whitehouse.gov/petition/maximize-public-benefit-federal-technology-sharing-government-developed-software-under-open-source/6n5ZBBwf" target="_blank">sign the petition</a> and get the word out through whatever channels you prefer (Twitter, Facebook, your own blog, whatever). </div>
<div>
<br /></div>
<div>
Unfortunately, the petition needs 25,000 signatures by August 16 to receive a White House response; with less than 700 signatures as of August 2, this seems unlikely. However, <i>this</i> petition could just be the beginning of a movement. The more publicity it gets, the more likely it will be that the effort will take off.</div>
<br />
<a href="https://twitter.com/JerryOnJava" class="twitter-follow-button" data-show-count="false">Follow @JerryOnJava</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com3tag:blogger.com,1999:blog-6466545174058573557.post-17101565816678768772012-06-22T12:37:00.000-04:002015-05-11T21:27:28.363-04:00Beware of Dojo Selects, Stores, and numeric IDsA handy feature of <a href="http://dojotoolkit.org/reference-guide/1.7/dijit/form/Select.html">Dijit Select</a> (or an extending widget such as <a href="http://dojotoolkit.org/reference-guide/1.7/dijit/form/FilteringSelect.html">FilteringSelect </a> or <a href="http://dojotoolkit.org/reference-guide/1.7/dijit/form/ComboBox.html">ComboBox</a>) is the integration with <a href="http://dojotoolkit.org/reference-guide/1.7/dojox/data.html">Dojo Data stores</a>. You can populate your Select/FilteringSelect/ComboBox with any data that can be accessed through a Dojo Data store, including JSON REST requests, HTTP queries, CSV files, or even Wikipedia.<br />
<br />
However, there is a limitation to this that has caused me problems, even though it's documented and I've run into it a couple times: Selects do not play nicely with stores that have non-string IDs (like integers). To quote from a <a href="http://dojotoolkit.org/documentation/tutorials/1.6/selects_using_stores/">Dojo tutorial</a>:<br />
<blockquote class="tr_bq" style="background-color: #cccccc; border: 2px solid #666; padding: 8px;">
dijit.form.Select possesses an important limitation: it is implemented in such a way that it does not handle non-string item identities well. Particularly, setting the current value of the widget programmatically via select.set("value", id) will not work with non-string (e.g. numeric) identities.</blockquote>
To drive this point home, I'll give a concrete example illustrating the problem. You can also see the example in action on <a href="http://dojoselectstores-site.orionhub.org:8080/dojoSelectStores/selectStoreExample.html">OrionHub </a>or <a href="https://www.opendrive.com/files/Nl8xODg0MTk2XzM3MlJRX2MyNjI/JerryOnJava%20-%20Dojo%20Select%20and%20Numeric%20Store.zip">download the source code</a> and run it yourself.<br /><br />
<h2>The goal</h2>
<div>
We're going to create a pair of Selects that will display a list of ships: one backed by a store with String IDs, and one backed by a store with numeric IDs. The generated page will look like this:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_P_5ZCJqGYyLR0Ue6gTRJ2QO3L8HLgICwEx4d7OF483ImskhCr1GE8fT-YMJORFvxeSw7Nx5qo5lz1x1KoLOz678S1JVFTMOmxBMzLdjzbASa_j1QCtCRAnGQqfO-pT4roD2nCe3uIw/s1600/Dijit+Select+Screenshot.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_P_5ZCJqGYyLR0Ue6gTRJ2QO3L8HLgICwEx4d7OF483ImskhCr1GE8fT-YMJORFvxeSw7Nx5qo5lz1x1KoLOz678S1JVFTMOmxBMzLdjzbASa_j1QCtCRAnGQqfO-pT4roD2nCe3uIw/s1600/Dijit+Select+Screenshot.PNG" /></a></div>
<br />
<h2>The data</h2>
<div>
Our store will be a <a href="http://dojotoolkit.org/reference-guide/1.7/dojo/data/ItemFileReadStore.html">dojo/data/ItemFileReadStore</a>, which will load JSON from a given file. The String ID JSON looks like this:</div>
<div>
<pre class="brush: js">{
"identifier": "shipId",
"label": "shipName",
"items": [
{ "shipId": "1", "shipName": "Constitution" },
{ "shipId": "2", "shipName": "Enterprise" },
// You get the point...
{ "shipId": "6", "shipName": "Yorktown" }
]
}
</pre>
</div>
<div>
And the numeric ID JSON looks like this:</div>
<div>
<pre class="brush: js">{
"identifier": "shipId",
"label": "shipName",
"items": [
{ "shipId": 1, "shipName": "Constitution" },
{ "shipId": 2, "shipName": "Enterprise" },
// You get the point...
{ "shipId": 6, "shipName": "Yorktown" }
]
}
</pre>
</div>
<h2>
The HTML</h2>
<div>
The HTML is pretty uninteresting; it basically loads the JavaScript files and throws in some DIV placeholders for the widgets:</div>
<pre class="brush: html"><html>
<head>
<link rel="stylesheet"
href="http://ajax.googleapis.com/ajax/libs/dojo/1.7/dijit/themes/claro/claro.css">
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/dojo.js"
data-dojo-config="async: true"></script>
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.7.2/dijit/dijit.js"
data-dojo-config="async: true"></script>
<script src="selectStoreExample.js"
data-dojo-config="async: true"></script>
</head>
<body class="claro">
<h1>Using String IDs</h1>
<div>
shipSelectString:
<div id="shipSelectString"></div>
<div id="selectStringEnterpriseButton"></div>
<div id="selectStringYorktownButton"></div>
</div>
<h1>Using Numeric IDs</h1>
<div>
shipSelectNumber:
<div id="shipSelectNumber"></div>
<div id="selectNumberEnterpriseButton"></div>
<div id="selectNumberYorktownButton"></div>
</div>
</body>
</html>
</pre>
<h2>
The JavaScript</h2>
<div>
Here's where all the Dijit bindings happen. For both the String and numeric ID stores, we create a Select and a couple buttons that call <b>select.set("value", <i>[the ID]</i>)</b>:</div>
<pre class="brush: js">require(["dojo", "dijit", "dojo/data/ItemFileReadStore", "dijit/form/Select",
"dijit/form/Button", "dojo/domReady!"
], function(dojo, dijit, ItemFileReadStore, Select, Button) {
//****** Using Strings for IDs ******
//Create the data store using a JSON file
var shipStoreString = new ItemFileReadStore({
url: "ships-string.json"
});
//Create and start the Select, using the ItemFileReadStore as its store
var selectString = new Select({
name: "shipSelectString",
store: shipStoreString
}, "shipSelectString");
selectString.startup();
//Create buttons that will use the Select widget's set() function to set the value
new Button({
label: "Set shipSelectString to Enterprise",
onClick: function() {
selectString.set("value", "2");
}
}, "selectStringEnterpriseButton");
new Button({
label: "Set shipSelectString to Yorktown",
onClick: function() {
selectString.set("value", "6");
}
}, "selectStringYorktownButton");
//****** Using numbers for IDs ******
//Create the data store using a JSON file
var shipStoreNumber = new ItemFileReadStore({
url: "ships-number.json"
});
//Create and start the Select, using the ItemFileReadStore as its store
var selectNumber = new Select({
name: "shipSelectNumber",
store: shipStoreNumber
}, "shipSelectNumber");
selectNumber.startup();
//Create buttons that will use the Select widget's set() function to set the value
new Button({
label: "Set shipSelectNumber to Enterprise",
onClick: function() {
selectNumber.set("value", 2);
}
}, "selectNumberEnterpriseButton");
new Button({
label: "Set shipSelectNumber to Yorktown",
onClick: function() {
selectNumber.set("value", 6);
}
}, "selectNumberYorktownButton");
});
</pre>
<div>
Now if you fire up the HTML page in your browser, you'll see the screen shown above in your browser. Click on the buttons, and you'll see that the Select with Strings as IDs changes when you click the buttons, but <em>nothing happens to the Select with numeric IDs</em>. This is the limitation (bug?) that prevents you from using numeric IDs in a store that's backing a Select.
<br />
<br />
<h2>
Resources</h2>
</div>
<div>
<ul>
<li><a href="http://dojotoolkit.org/documentation/tutorials/1.6/selects_using_stores/">Advanced Dijit Selects using Stores</a></li>
<li><a href="http://dojoselectstores-site.orionhub.org:8080/dojoSelectStores/selectStoreExample.html">Running example on OrionHub </a></li>
<li> <a href="https://www.opendrive.com/files/Nl8xODg0MTk2XzM3MlJRX2MyNjI/JerryOnJava%20-%20Dojo%20Select%20and%20Numeric%20Store.zip">Example source code</a></li>
</ul>
</div>
<link href="http://alexgorbatchev.com/pub/sh/2.1.364/styles/shCore.css" rel="stylesheet" type="text/css"></link> <link href="http://alexgorbatchev.com/pub/sh/2.1.364/styles/shThemeDefault.css" rel="stylesheet" type="text/css"></link> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shCore.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushXml.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushJScript.js" type="text/javascript">
</script> <script type="text/javascript">
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.defaults['toolbar'] = true;
SyntaxHighlighter.all();
</script>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com1tag:blogger.com,1999:blog-6466545174058573557.post-55084392870733634812012-05-16T07:54:00.000-04:002016-07-22T12:46:03.886-04:00Secure Password Storage - Lots of don'ts, a few dos, and a concrete Java SE example<p><i>Note: this post frequently refers to "encrypting" passwords, a term that usually implies that they could be decrypted. We're really talking about doing a one-way hash. I used the term "encrypt" to make it more accessible to those who are less familiar with cryptography, but "hash" would have been more precise.</i></p>
<h2>
The importance of storing passwords securely</h2>
<div>
As software developers, one of our most important responsibilities is the protection of our users' personal information. Without technical knowledge of our applications, users have no choice but to trust that we're fulfilling this responsibility. Sadly, when it comes to passwords, the software development community has a spotty track record.</div>
<div>
<br />
While it's impossible to build a 100% secure system, there are fortunately some simple steps we can take to make our users' passwords safe enough to send would-be hackers in search of easier prey.<br />
<br />
If you don't want all the background, feel free to <a href="#example">skip to the Java SE example below</a>.
<br />
<br /></div>
<h2>
The Don'ts</h2>
<div>
First, let's quickly discuss some of the things you shouldn't do when building an application that requires authentication:</div>
<div>
<ul>
<li><b>Don't store authentication data unless you really have to. </b>This may seem like a cop-out, but before you start building a database of user credentials, consider letting someone else handle it. If you're building a public application, consider using <a href="http://oauth.net/" target="_blank">OAuth</a> providers such as <a href="https://developers.google.com/accounts/docs/OAuth2Login" target="_blank">Google</a> or <a href="https://developers.facebook.com/docs/authentication/" target="_blank">Facebook</a>. If you're building an internal enterprise application, consider using any internal authentication services that may already exist, like a corporate LDAP or Kerberos service. Whether it's a public or internal application, your users will appreciate not needing to remember another user ID and password, and it's one less database out there for hackers to attack.</li>
<li><b>If you must store authentication data, for Gosling's sake don't store the passwords in clear text</b>. This should be obvious, but it bears mentioning. Let's at least make the hackers break a sweat.</li>
<li><b>Don't use two-way encryption unless you really need to retrieve the clear-text password. </b>You only need to know their clear-text password if you are using their credentials to interact with an external system on their behalf. Even then, you're better off having the user authenticate with that system directly. To be clear, <b>you do not need to use the user's original clear-text password to perform authentication in your application</b>. I'll go into more detail on this later, but when performing authentication, you will be applying an encryption algorithm to the password the user entered and comparing it to the encrypted password you've stored. </li>
<li><b>Don't use outdated hashing algorithms like MD5</b>. Honestly, hashing a password with MD5 is virtually useless. Here's an MD5-hashed password: <b>569a70c2ccd0ac41c9d1637afe8cd932</b>. Go to <a href="http://www.md5hacker.com/">http://www.md5hacker.com/</a> and you can decrypt it in seconds.</li>
<li><b>Don't come up with your own encryption scheme. </b>There are a handful of brilliant encryption experts in the world that are capable of outwitting hackers and devising a new encryption algorithm. I am not one of them, and most likely, neither are you. If a hacker gets access to your user database, they can probably get your code too. Unless you've invented the next great successor to <a href="http://en.wikipedia.org/wiki/PBKDF2" target="_blank">PBKDF2</a> or <a href="http://bcrypt.sourceforge.net/" target="_blank">bcrypt</a>, they will be cackling maniacally as they quickly crack all your users' passwords and publish them on the <a href="http://en.wikipedia.org/wiki/Darknet_(file_sharing)" target="_blank">darknet</a>.</li>
</ul>
<br /></div>
<h2>
The Dos</h2>
<div>
Okay, enough lecturing on what not to do. Here are the things you need to focus on:</div>
<div>
<ul>
<li><b>Choose a one-way encryption algorithm.</b> As I mentioned above, once you've encrypted and stored a user's password, you never need to know the real value again. When a user attempts to authenticate, you'll just apply the same algorithm to the password they entered, and compare that to the encrypted password that you stored.</li>
<li><b>Make the encryption as slow as your application can tolerate</b>. Any modern password encryption algorithm should allow you to provide parameters that increase the time needed to encrypt a password (i.e. in PBKDF2, specifying the number of iterations). Why is slow good? Your users won't notice if it takes an extra 100ms to encrypt their password, but a hacker trying a brute-force attack will notice the difference as they run the algorithm billions of times.</li>
<li><b>Pick a well-known algorithm</b>. The National Institute of Standards and Technology (NIST) <a href="http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf" target="_blank">recommends PBKDF2</a> for passwords. bcrypt is a popular and established alternative, and <a href="http://www.tarsnap.com/scrypt.html" target="_blank">scrypt</a> is a relatively new algorithm that has been well-received. All these are popular for a reason: they're good. </li>
</ul>
<br /></div>
<h2>
PBKDF2</h2>
<div>
Before I give show you some concrete code, let's talk a little about why PBKDF2 is a good choice for encrypting passwords:<br />
<div style="float: right; margin: 0px 0px 10px 10px;"><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- Article inline -->
<ins class="adsbygoogle"
style="display:inline-block;width:300px;height:250px"
data-ad-client="ca-pub-4657506819321826"
data-ad-slot="3700917392"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></div>
<ul>
<li><b>Recommended by the NIST. </b>Section 5.3 of <a href="http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf" target="_blank">Special Publication 800-132</a> recommends PBKDF2 for encrypting passwords. Security officials will love that.</li>
<li><b>Adjustable key stretching to defeat brute force attacks</b>. The basic idea of <a href="http://en.wikipedia.org/wiki/Key_stretching" target="_blank">key stretching</a> is that after you apply your hashing algorithm to the password, you then continue to apply the same algorithm to the result many times (the iteration count). If hackers are trying to crack your passwords, this greatly increases the time it takes to try the billions of possible passwords. As mentioned previously, the slower, the better. PBKDF2 lets you specify the number of iterations to apply, allowing you to make it as slow as you like.</li>
<li><b>A required salt to defeat rainbow table attacks and prevent collisions with other users.</b> A <a href="http://en.wikipedia.org/wiki/Salt_(cryptography)" target="_blank">salt</a> is a randomly generated sequence of bits that is unique to each user and is added to the user's password as part of the hashing. This prevents <a href="http://en.wikipedia.org/wiki/Rainbow_table" target="_blank">rainbow table attacks</a> by making a precomputed list of results unfeasible. And since each user gets their own salt, even if two users have the same password, the encrypted values will be different. There is a lot of conflicting information out there on whether the salts should be stored someplace separate from the encrypted passwords. Since the key stretching in PBKDF2 already protects us from brute-force attacks, I feel it is unnecessary to try to hide the salt. Section 3.1 of NIST SP 800-132 also defines salt as a "non-secret binary value," so that's what I go with.</li>
<li><b>Part of Java SE 6</b>. No additional libraries necessary. This is particularly attractive to those working in environments with restrictive open-source policies.</li>
</ul>
<br /></div>
<h2>
<a href="http://www.blogger.com/blogger.g?blogID=6466545174058573557" name="example"></a>Finally, a concrete example</h2>
<div>
Okay, here's some code to encrypt passwords using PBKDF2. Only Java SE 6 is required.</div>
<pre class="brush: java">import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Arrays;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
public class PasswordEncryptionService {
public boolean authenticate(String attemptedPassword, byte[] encryptedPassword, byte[] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
// Encrypt the clear-text password using the same salt that was used to
// encrypt the original password
byte[] encryptedAttemptedPassword = getEncryptedPassword(attemptedPassword, salt);
// Authentication succeeds if encrypted password that the user entered
// is equal to the stored hash
return Arrays.equals(encryptedPassword, encryptedAttemptedPassword);
}
public byte[] getEncryptedPassword(String password, byte[] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
// PBKDF2 with SHA-1 as the hashing algorithm. Note that the NIST
// specifically names SHA-1 as an acceptable hashing algorithm for PBKDF2
String algorithm = "PBKDF2WithHmacSHA1";
// SHA-1 generates 160 bit hashes, so that's what makes sense here
int derivedKeyLength = 160;
// Pick an iteration count that works for you. The NIST recommends at
// least 1,000 iterations:
// http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf
// iOS 4.x reportedly uses 10,000:
// http://blog.crackpassword.com/2010/09/smartphone-forensics-cracking-blackberry-backup-passwords/
int iterations = 20000;
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength);
SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);
return f.generateSecret(spec).getEncoded();
}
public byte[] generateSalt() throws NoSuchAlgorithmException {
// VERY important to use SecureRandom instead of just Random
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
// Generate a 8 byte (64 bit) salt as recommended by RSA PKCS5
byte[] salt = new byte[8];
random.nextBytes(salt);
return salt;
}
}
</pre>
<br />
The flow goes something like this:<br />
<ol>
<li>When adding a new user, call <b>generateSalt()</b>, then <b>getEncryptedPassword()</b>, and store both the encrypted password and the salt. <b>Do not store the clear-text password.</b> Don't worry about keeping the salt in a separate table or location from the encrypted password; as discussed above, the salt is non-secret.</li>
<li>When authenticating a user, retrieve the previously encrypted password and salt from the database, then send those and the clear-text password they entered to <b>authenticate()</b>. If it returns true, authentication succeeded.</li>
<li>When a user changes their password, it's safe to reuse their old salt; you can just call <b>getEncryptedPassword() </b>with the old salt.</li>
</ol>
<div>
Easy enough, right? If you're building or maintaining an application that violates any of the "don'ts" above, then <i>please</i> do your users a favor and use something like PBKDF2 or bcrypt. Help them, Obi-Wan Developer, you're their only hope.
<br /><br /></div>
<h2>
References</h2>
<div>
<ul>
<li>NIST: <a href="http://csrc.nist.gov/publications/nistpubs/800-132/nist-sp800-132.pdf" target="_blank">Special Publication 800-132</a></li>
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/PBKDF2" target="_blank">PBKDF2</a> </li>
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Key_stretching" target="_blank">Key Stretching</a> </li>
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Salt_(cryptography)" target="_blank">Salt (cryptography)</a></li>
<li>Wikipedia: <a href="http://en.wikipedia.org/wiki/Rainbow_table" target="_blank">Rainbow Table Attacks</a></li>
<li>Vladimir Katalov: <a href="http://blog.crackpassword.com/2010/09/smartphone-forensics-cracking-blackberry-backup-passwords/" target="_blank">Smartphone Forensics: Cracking BlackBerry Backup Passwords </a></li>
</ul>
</div>
<div>
</div>
<link href="http://alexgorbatchev.com/pub/sh/2.1.364/styles/shCore.css" rel="stylesheet" type="text/css"></link> <link href="http://alexgorbatchev.com/pub/sh/2.1.364/styles/shThemeDefault.css" rel="stylesheet" type="text/css"></link> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shCore.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushXml.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushCss.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushJava.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushPhp.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushJScript.js" type="text/javascript">
</script> <script type="text/javascript">
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.defaults['toolbar'] = true;
SyntaxHighlighter.all();
</script>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com20tag:blogger.com,1999:blog-6466545174058573557.post-40946226972483597792012-01-16T22:19:00.000-05:002015-05-11T21:27:44.165-04:00JSF and the "immediate" Attribute - Command ComponentsThe <b>immediate </b>attribute in JSF is commonly misunderstood. If you don't believe me, check out <a href="http://stackoverflow.com/search?q=jsf+immediate">Stack Overflow</a>. Part of the confusion is likely due to <b>immediate </b>being available on both input (i.e.. <h:inputText />) and command (i.e. <h:commandButton />) components, each of which affects the JSF lifecycle differently.<br />
<br />
Here is the standard JSF lifecycle:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisiIkx4M1J_WZCAlIX-q9aLkwHInXGquSPAD3CmNEqHbPnj71p6cSXy0IqVGZyfCvISpQfXpd5hyphenhyphenTXCCc50GwTHy8y_vBP1IgmpLtLS9zax9j_kcAJ71ScJiQAp3H1av1N4kEBaHXI-g/s1600/JSF+Lifecycle+-+Standard.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisiIkx4M1J_WZCAlIX-q9aLkwHInXGquSPAD3CmNEqHbPnj71p6cSXy0IqVGZyfCvISpQfXpd5hyphenhyphenTXCCc50GwTHy8y_vBP1IgmpLtLS9zax9j_kcAJ71ScJiQAp3H1av1N4kEBaHXI-g/s1600/JSF+Lifecycle+-+Standard.png" /></a></div><br />
For the purposes of this article, I'll assume you are familiar with the basics of the JSF lifecycle. If you need an introduction or a memory refresher, check out the <a href="http://docs.oracle.com/javaee/6/tutorial/doc/bnaqq.html">Java EE 6 Tutorial - The Lifecycle of a JavaServer Faces Application</a>.<br />
<br />
<i>Note: the code examples in this article are for JSF 2 (Java EE 6), but the principals are the same for JSF 1.2 (Java EE 5).</i><br />
<br />
<h2>immediate=true on Command components</h2>In the <i>standard</i> JSF lifecycle, the action attribute on an Command component is evaluated in the <b>Invoke Application</b> phase. For example, say we have a <b>User </b>entity/bean:<br />
<br />
<pre class="brush: java">public class User implements Serializable {
@NotBlank
@Length(max = 50)
private String firstName;
@NotBlank
@Length(max = 50)
private String lastName;
/* Snip constructors, getters/setters, a nice toString() method, etc */
}</pre><br />
And a <b>UserManager </b>to serve as our managed bean:<br />
<br />
<pre class="brush: java">@SessionScoped
@ManagedBean
public class UserManager {
private User newUser;
/* Snip some general page logic... */
public String addUser() {
//Snip logic to persist newUser
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("User " + newUser.toString() + " added"));
return "/home.xhtml";
}
</pre><br />
And a basic Facelets page, <b>newUser.xhtml</b>, to render the view:<br />
<br />
<pre class="brush: xml"><h:form>
<h:panelGrid columns="2">
<h:outputText value="First Name: " />
<h:panelGroup>
<h:inputText id="firstName"
value="#{userManager.newUser.firstName}" />
<h:message for="firstName" />
</h:panelGroup>
<h:outputText value="Last Name: " />
<h:panelGroup>
<h:inputText id="lastName" value="#{userManager.newUser.lastName}" />
<h:message for="lastName" />
</h:panelGroup>
</h:panelGrid>
<h:commandButton value="Add User" action="#{userManager.addUser()}" />
</h:form></pre><br />
Which all combine to produce this lovely form:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGXxwNHs9ULnxINJnvwKpn8mlhL-urlsqT8tJFQqsrxx1POr5MFNz9238RrKr4IwHfRdGDaRbLhJgisPNIj1OwY0VLJ1I7MOvVzGGYtcTNjG94VjbljxYPhKi3KtkXjhFCaf-0B3FMHw/s1600/Form+screenshot+-+basic.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGXxwNHs9ULnxINJnvwKpn8mlhL-urlsqT8tJFQqsrxx1POr5MFNz9238RrKr4IwHfRdGDaRbLhJgisPNIj1OwY0VLJ1I7MOvVzGGYtcTNjG94VjbljxYPhKi3KtkXjhFCaf-0B3FMHw/s320/Form+screenshot+-+basic.png" width="320" /></a></div><br />
When the user clicks on the <b>Add User</b> button, <b>#{userManager.addUser}</b> will be called in the <b>Invoke Application</b> phase; this makes sense, because we want the input fields to be validated, converted, and applied to newUser before it is persisted.<br />
<br />
Now let's add a "cancel" button to the page, in case the user changes his/her mind. We'll add another <h:commandButton /> to the page:<br />
<br />
<pre class="brush: xml"><h:form>
<!-- Snip Input components -->
<h:commandButton value="Add User" action="#{userManager.addUser()}" />
<h:commandButton value="Cancel" action="#{userManager.cancel()}" />
</h:form></pre><br />
And the <b>cancel()</b> method to <b>UserManager</b>:<br />
<br />
<pre class="brush: java">public String cancel() {
newUser = new User();
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("Cancelled new user"));
return "/home.xhtml";
}</pre><br />
Looks good, right? But when we actually try to use the cancel button, we get errors complaining that first and last name are required:<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1sGj1BrD2uq4Nc-eWq5H2nekOsyA97dDUY0Ys2-k1sic6fDJ386fCMUIeQiSUDu_dlEzjOn0V1Ts8V_ptjFgrU-75xBqLxzahfXPFGT2RGScnebcZWZM5iU7qAoIzyaKFjS8-HrcOEA/s1600/JSF+Lifecycle+-+Cancel+without+immediate.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="123" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1sGj1BrD2uq4Nc-eWq5H2nekOsyA97dDUY0Ys2-k1sic6fDJ386fCMUIeQiSUDu_dlEzjOn0V1Ts8V_ptjFgrU-75xBqLxzahfXPFGT2RGScnebcZWZM5iU7qAoIzyaKFjS8-HrcOEA/s320/JSF+Lifecycle+-+Cancel+without+immediate.png" width="320" /></a></div><br />
<div style="float: right; margin: 0px 0px 10px 10px;"><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- Article inline -->
<ins class="adsbygoogle"
style="display:inline-block;width:300px;height:250px"
data-ad-client="ca-pub-4657506819321826"
data-ad-slot="3700917392"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></div>
This is because <b>#{userManager.cancel}</b> isn't called until the <b>Invoke Application</b> phase, which occurs <i>after </i>the <b>Process Validations</b> phase; since we didn't enter a first and last name, the validations failed before <b>#{userManager.cancel}</b> is called, and the response is rendered after the <b>Process Validations</b> phase.<br />
<br />
We certainly don't want to require the end user to enter a valid user before cancelling! Fortunately, JSF provides the <b>immediate </b>attribute on Command components. When <b>immediate </b>is set to true on an Command component, the action is invoked in the <b>Apply Request Values</b> phase:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbjeXY1t1gbrtuGGVHeX8xmcs_vdwGE14-Z1pMgXwZnM0xp8UD35DuERNqKTpblbd89OF6P8Tt1qVU1nnB0l_fSYYaYhh2AETYQwBmaYV3Vd3bbSgbnxaZrPZIy6v6v3r8RnmSHIMURw/s1600/JSF+Lifecycle+-+Immediate+on+Command+Component.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbjeXY1t1gbrtuGGVHeX8xmcs_vdwGE14-Z1pMgXwZnM0xp8UD35DuERNqKTpblbd89OF6P8Tt1qVU1nnB0l_fSYYaYhh2AETYQwBmaYV3Vd3bbSgbnxaZrPZIy6v6v3r8RnmSHIMURw/s1600/JSF+Lifecycle+-+Immediate+on+Command+Component.png" /></a></div><br />
This is perfect for our Cancel use case. If we add <b>immediate=true</b> to the Cancel <h:commandbutton>, <b>#{userManager.cancel}</b> will be called in the <b>Apply Request Values</b> phase, before any validation occurs. <br />
<br />
</h:commandbutton><br />
<pre class="brush: xml"><h:form>
<!-- Snip Input components -->
<h:commandButton value="Add User" action="#{userManager.addUser()}" />
<h:commandButton value="Cancel" action="#{userManager.cancel()}" immediate="true" />
</h:form></pre><br />
So now when we click cancel, <b>#{userManager.cancel}</b> is called in the <b>Apply Request Values</b> phase, and we are directed back to the home page with the expected cancellation message; no validation errors!<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiap0oP7FPDHqbZfgcEa2NQG-q1SYEk4dD5Bneb5Ws1yxqblYjoItIxswgxh4vzP9vwndc6NqTxVo1slhjRlznOF7xgEYgvep6zHUWCIGopxMHGAryfCruaI0W86t7TwHH9qUnDVGyXtQ/s1600/Form+screenshot+-+immediate+on+cancel+button.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiap0oP7FPDHqbZfgcEa2NQG-q1SYEk4dD5Bneb5Ws1yxqblYjoItIxswgxh4vzP9vwndc6NqTxVo1slhjRlznOF7xgEYgvep6zHUWCIGopxMHGAryfCruaI0W86t7TwHH9qUnDVGyXtQ/s1600/Form+screenshot+-+immediate+on+cancel+button.png" /></a></div><br />
<h2>What about Input components?</h2>Input components have the <b>immediate</b> attribute as well, which also moves all their logic into the <b>Apply Request Values</b> phase. However, the behavior is slightly different from Command components, especially depending on whether or not the validation on the Input component succeeds. My next article will address <b>immediate=true</b> on Input components. For now, here's a preview of how the JSF lifecycle is affected:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6V3So0-w2a9yB2ifw4GJa3rsYVVm23vyzN03TpgC7SWf9-KxrhvbRMlf5QPXoeuHB6SxpLFrUJlsNmmZrunzI-ywGdqDKYziDa43kwqOE2NDkDsybSZwa-rAzzZOx1Lfoq4BddGWc8g/s1600/JSF+Lifecycle+-+Immediate+on+Input+Component+-+no+errors.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6V3So0-w2a9yB2ifw4GJa3rsYVVm23vyzN03TpgC7SWf9-KxrhvbRMlf5QPXoeuHB6SxpLFrUJlsNmmZrunzI-ywGdqDKYziDa43kwqOE2NDkDsybSZwa-rAzzZOx1Lfoq4BddGWc8g/s1600/JSF+Lifecycle+-+Immediate+on+Input+Component+-+no+errors.png" /></a></div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs2BNVh8AXEt5JXRwfBXJHaE9sOhn4oR1iO1g4ZmlzSNLC-Hx5_TODSniRxue1je5vnwwZ3DbtIbN2RGHjFg5_F5nMjmB7-SXT2lauNIaMGTLe6WP6n-J3IfbJKrurTflAgMr6Vz-q6g/s1600/JSF+Lifecycle+-+Immediate+on+Input+Component+-+with+errors.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs2BNVh8AXEt5JXRwfBXJHaE9sOhn4oR1iO1g4ZmlzSNLC-Hx5_TODSniRxue1je5vnwwZ3DbtIbN2RGHjFg5_F5nMjmB7-SXT2lauNIaMGTLe6WP6n-J3IfbJKrurTflAgMr6Vz-q6g/s1600/JSF+Lifecycle+-+Immediate+on+Input+Component+-+with+errors.png" /></a></div><br />
<br />
<br />
<link href="http://alexgorbatchev.com/pub/sh/2.1.364/styles/shCore.css" rel="stylesheet" type="text/css"></link> <link href="http://alexgorbatchev.com/pub/sh/2.1.364/styles/shThemeDefault.css" rel="stylesheet" type="text/css"></link> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shCore.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushXml.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushCss.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushJava.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushPhp.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushJScript.js" type="text/javascript">
</script> <script type="text/javascript">
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.defaults['toolbar'] = true;
SyntaxHighlighter.all();
</script>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com4tag:blogger.com,1999:blog-6466545174058573557.post-76777712317837635002011-10-13T15:27:00.000-04:002015-05-11T21:27:57.798-04:00Replacement for s:decorate in Seam 3I've been doing a gap analysis for our migration from Seam 2 to Seam 3, and I was dismayed to find that the <s:decorate> tag is gone! In Seam 2, you create a template like this:<br />
<br />
<pre class="brush: xml"><ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:s="http://jboss.com/products/seam/taglib">
<div class="prop">
<s:label styleClass="nameEdit #{invalid?'errors':''}">
<s:span styleClass="required"
rendered="#{required}">*</s:span>
<ui:insert name="label"/>
</s:label>
<span class="value #{invalid?'errors':''}">
<s:validateAll>
<ui:insert/>
</s:validateAll>
</span>
<span class="error">
<h:graphicImage value="/img/error.gif"
rendered="#{invalid}" styleClass="errors"/>
</span>
</div>
</ui:composition></pre><br />
And then reference it using <s:decorate><br />
<br />
<pre class="brush: xml"><s:decorate template="edit.xhtml">
<ui:define name="label">Country:</ui:define>
<h:inputText value="#{location.country}" required="true"/>
</s:decorate></pre><br />
And now required fields are noted with an asterisk (*), all fields are automatically validated, and when they have errors, a special style is applied and the error message appears to the right of the field:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNlvIvoZdTcfWFT2rCaVYmpBqyQ77Ei5nCjFxVd7rfeAw0-wXxZJpHAgDlfvpnYUkEVu4WHVzxA04jBoC9lk5ZOkEWjca2nLRpHYu4mFvBxqnVbZ73JbOzjNtPZroV7sqB65Hz6YMxxA/s1600/decorate+screenshot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNlvIvoZdTcfWFT2rCaVYmpBqyQ77Ei5nCjFxVd7rfeAw0-wXxZJpHAgDlfvpnYUkEVu4WHVzxA04jBoC9lk5ZOkEWjca2nLRpHYu4mFvBxqnVbZ73JbOzjNtPZroV7sqB65Hz6YMxxA/s320/decorate+screenshot.png" /></a></div><br />
<i>Note: this is all documented in <a href="http://docs.jboss.org/seam/2.2.2.Final/reference/en-US/html_single/#d0e29026">Section 33.1.13 of the Seam 2 reference</a></i>.<br />
<br />
Pretty slick! I definitely need this functionality when I migrate to Seam 3, but the <s:decorate> tag is gone, and I had a hard time finding a replacement.<br />
<br />
<h2>Replacing with UIInputContainer</h2>Fortunately, a close replacement actually exists in Seam 3's Faces module... it just isn't described as such! Seam Faces provides a component called <a href="http://docs.jboss.org/seam/3/faces/latest/reference/en-US/html/components.html#UIInputContainer">UIInputContainer</a>. When this is combined with a JSF 2 composite component, you can get the same functionality.<br />
<br />
First, create your composite component. I created mine at <b>WebContent/resources/orr/decorate.xhtml</b>:<br />
<br />
<pre class="brush: xml"><?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface componentType="org.jboss.seam.faces.InputContainer" />
<composite:implementation>
<div>
<h:outputLabel id="label" value="#{cc.attrs.label}:"
styleClass="#{cc.attrs.invalid ? 'invalid' : ''}">
<h:outputText styleClass="required" rendered="#{cc.attrs.required}"
value="*" />
</h:outputLabel>
<!-- h:panelGroup is a workaround for a JSF bug, see http://java.net/jira/browse/JAVASERVERFACES-1991 -->
<h:panelGroup styleClass="value #{invalid?'errors':''}" >
<composite:insertChildren />
</h:panelGroup>
<h:message id="message" errorClass="invalid message"
rendered="#{cc.attrs.invalid}" />
</div>
</composite:implementation>
</html>
</pre><br />
Since I put the composite component in <b>WebContent/resources/orr/decorate.xhtml</b>, the namespace is <b>http://java.sun.com/jsf/composite/<i>orr</i></b> and the tag name is <b>decorate</b>.<br />
<br />
Now use this new tag in your Facelets page:<br />
<pre class="brush: xml"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:o="http://java.sun.com/jsf/composite/orr">
<o:decorate label="Country:">
<h:inputText value="#{location.country}" required="true"/>
</o:decorate>
</pre><br />
And that's it! This will generate roughly the same output and behavior as Seam 2's <s:decorate> tag. So all along, there was a pretty good replacement, but either this wasn't made clear anywhere, or my Google skills aren't quite as good as I think. I imagine this would be documented in JBoss's Seam 2 to Seam 3 migration guide, if such a thing existed...<br />
<br />
<link href="http://alexgorbatchev.com/pub/sh/2.1.364/styles/shCore.css" rel="stylesheet" type="text/css"></link> <link href="http://alexgorbatchev.com/pub/sh/2.1.364/styles/shThemeDefault.css" rel="stylesheet" type="text/css"></link> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shCore.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushXml.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushCss.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushJava.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushPhp.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushJScript.js" type="text/javascript">
</script> <script type="text/javascript">
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.defaults['toolbar'] = true;
SyntaxHighlighter.all();
</script>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com5tag:blogger.com,1999:blog-6466545174058573557.post-37114331755062043012011-10-07T14:46:00.000-04:002015-05-11T21:28:32.613-04:00Creating a JSF 1.2 Custom Converter with AttributesCustom converters are a very important part of many JSF applications. Writing and using a basic converter is quite simple if it has no attributes:<br />
<br />
<pre class="brush: xml"><h:outputText value="#{somePhoneNumber}"
converter="myPhoneNumberConverter" />
</pre><br />
However, things get a little trickier when you need to provide attributes to your converter. For example, Facelets includes a date/time converter:<br />
<br />
<pre class="brush: xml"><h:outputText value="#{someDate}">
<f:convertDateTime type="both" dateStyle="short"/>
</h:outputText>
</pre><br />
While there are many resources out there on creating basic custom converters, I had difficulty finding a good explanation of how to create custom converters with attributes. Here are the steps I followed:<br />
<br />
<i>Note: I built this using Seam 2.2 on JBoss EAP 5.1, but this should work for any JSF 1.2 application using Facelets.</i><br />
<br />
<h2>The USAPhoneNumber class</h2>We'll be creating a converter for a class called USAPhoneNumber. There's nothing special about this class, just a POJO with an attribute for each "part" of a US phone number.<br />
<br />
<pre class="brush: java">package org.orr.customconverter;
import java.io.Serializable;
public class USAPhoneNumber implements Serializable {
private static final long serialVersionUID = 1L;
private String areaCode;
private String prefix;
private String lineNumber;
private String extension;
public USAPhoneNumber(String areaCode, String prefix, String lineNumber,
String extension) {
super();
this.areaCode = areaCode;
this.prefix = prefix;
this.lineNumber = lineNumber;
this.extension = extension;
}
public USAPhoneNumber(String areaCode, String prefix, String lineNumber) {
super();
this.areaCode = areaCode;
this.prefix = prefix;
this.lineNumber = lineNumber;
}
public String getAreaCode() {
return areaCode;
}
public String getPrefix() {
return prefix;
}
public String getLineNumber() {
return lineNumber;
}
public String getExtension() {
return extension;
}
@Override
public String toString() {
String tmp = areaCode + "-" + prefix + "-" + lineNumber;
if (extension != null && extension.length() > 0)
tmp += " x" + extension;
return tmp;
}
}
</pre><br />
<h2>Create a Converter class</h2>First we'll create an implementation of <b>javax.faces.convert.Converter</b>. We might want the ability to convert it into a few different styles, such as 212-555-7456, (212) 555-7456, 212 555 7456, etc. To support this, we are creating an attribute called <b>style</b>, which will accept values like <b>parentheses</b>, <b>dashes</b>, and <b>spaces</b>.<br />
<br />
<pre class="brush: java">package org.orr.customconverter;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
public class PhoneNumberConverter implements Converter, Serializable {
private static final long serialVersionUID = 1L;
private String style;
private static final Style DEFAULT_STYLE = Style.DASHES;
private enum Style {
DASHES, SPACES, PARENTHESES
};
public Object getAsObject(FacesContext context, UIComponent component,
String stringValue) {
if (stringValue == null || stringValue.trim().length() == 0)
return null;
// We COULD try to read in the value based on the style, but in this
// case, it's easiest to just strip out all non-numeric characters and
// require that the number be greater than 10 digits, with any digits
// past 10 becoming the extension
String rawNumber = stringValue.replaceAll("[^0-9]", "");
USAPhoneNumber number = null;
if (rawNumber.length() < 10)
throw new ConverterException(new FacesMessage(
"Phone number must have at least 10 numeric characters"));
else if (rawNumber.length() == 10)
number = new USAPhoneNumber(rawNumber.substring(0, 3),
rawNumber.substring(3, 6), rawNumber.substring(6));
else
number = new USAPhoneNumber(rawNumber.substring(0, 3),
rawNumber.substring(3, 6), rawNumber.substring(6, 10),
rawNumber.substring(10));
return number;
}
public String getAsString(FacesContext context, UIComponent component,
Object value) {
USAPhoneNumber number = (USAPhoneNumber) value;
if (number == null)
return "";
String stringValue = null;
Style styleEnum = style == null ? DEFAULT_STYLE : Style.valueOf(style
.toUpperCase());
switch (styleEnum) {
case DASHES:
stringValue = number.getAreaCode() + "-" + number.getPrefix() + "-"
+ number.getLineNumber() + getFormattedExtension(number);
break;
case SPACES:
stringValue = number.getAreaCode() + " " + number.getPrefix() + " "
+ number.getLineNumber() + getFormattedExtension(number);
break;
case PARENTHESES:
stringValue = "(" + number.getAreaCode() + ") "
+ number.getPrefix() + "-" + number.getLineNumber()
+ getFormattedExtension(number);
break;
default:
throw new ConverterException(new FacesMessage("Unsupported style: "
+ style));
}
return stringValue;
}
private String getFormattedExtension(USAPhoneNumber number) {
if (number.getExtension() == null)
return "";
else
return " x" + number.getExtension();
}
public String getStyle() {
return style;
}
public void setStyle(String style) {
this.style = style;
}
}
</pre>
<div style="float: right"><script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- Article inline -->
<ins class="adsbygoogle"
style="display:inline-block;width:300px;height:250px"
data-ad-client="ca-pub-4657506819321826"
data-ad-slot="3700917392"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></div>
If you've written a JSF converter before, this will look pretty familiar. However, there are a few things to note: <br />
<ol><li><b>You must implement java.io.Serializable.</b> After the RENDER RESPONSE phase, JSF serializes the view; in the RENDER RESPONSE phase, it deserializes it. If your converter does not implement Serializable, the attribute(s) (<b>style</b> in this example) will be lost.</li>
<li><b>You must not make your converter a Seam component</b>. Seam provides some handy annotations to save some of the configuration overhead in creating a converter (see <a href="http://docs.jboss.org/seam/2.2.0.GA/reference/en-US/html/controls.html#controls.annotations">section 33.2 in the Seam reference</a> for details). However, if you are using the same converter with different attribute values on the same page, Seam will reuse the same instance with the same attribute values on the entire page. <i>Note: this might be avoidable by using the STATELESS scope, but I haven't tried it</i>.</li>
</ol><br />
<h2>Create taglib.xml</h2>Now we need to create a Facelets tag library definition. We'll call it <b>orr-taglib.xml</b> and put it in <b>WebContent/META-INF</b>:<br />
<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
<namespace>http://jerryorr.blogspot.com/customConverterTaglib</namespace>
<tag>
<tag-name>convertPhoneNumber</tag-name>
<converter>
<converter-id>orr.convertPhoneNumber</converter-id>
</converter>
</tag>
</facelet-taglib>
</pre><br />
We also need to register the taglib in web.xml:<br />
<br />
<pre class="brush: xml"><context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/META-INF/orr-taglib.xml</param-value>
</context-param>
</pre><br />
<h2>Register converter in faces-config.xml</h2>Next, we need to register our converter in faces-config.xml.<i> Note: this is one of those steps that Seam can save for us, but since we aren't making this a Seam component, we need to register the converter manually</i>.<br />
<br />
<pre class="brush: xml"><converter>
<converter-id>orr.convertPhoneNumber</converter-id>
<converter-class>org.orr.customconverter.PhoneNumberConverter</converter-class>
</converter>
</pre><br />
<h2>Create a TLD</h2>Finally, we'll create a tag library descriptor. This step is not strictly necessary, but Eclipse will use it for autocomplete.<br />
<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd">
<tlib-version>2.0</tlib-version>
<short-name>n</short-name>
<uri>http://jerryorr.blogspot.com/customConverterTaglib</uri>
<tag>
<description>Converts a USAPhoneNumber.</description>
<name>convertPhoneNumber</name>
<tag-class>org.orr.customconverter.PhoneNumberConverter</tag-class>
<body-content>JSP</body-content>
<attribute>
<description>Style to display the phone number. Valid values include parentheses, dashes, spaces</description>
<name>style</name>
<rtexprvalue>true</rtexprvalue>
<deferred-value>
<type>java.lang.String</type>
</deferred-value>
</attribute>
</tag>
</taglib>
</pre><br />
<h2>Using the converter</h2>Now we can use our phone number converter! We'll create a simple Seam component to interact with:<br />
<br />
<pre class="brush: java">package org.orr.customconverter;
import java.io.Serializable;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.international.StatusMessage.Severity;
import org.jboss.seam.international.StatusMessages;
@Name("updatePhoneNumberAction")
@Scope(ScopeType.SESSION)
public class UpdatePhoneNumberAction implements Serializable {
private static final long serialVersionUID = 1L;
private USAPhoneNumber phoneNumber = new USAPhoneNumber("212", "555",
"3456");
@In
StatusMessages statusMessages;
public USAPhoneNumber getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(USAPhoneNumber phoneNumber) {
this.phoneNumber = phoneNumber;
}
public void update() {
statusMessages.add(Severity.INFO, "Phone number updated: "
+ phoneNumber);
}
}
</pre><br />
And a simple Facelets view to interact with it:<br />
<br />
<pre class="brush: xml"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<f:view xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:o="http://jerryorr.blogspot.com/customConverterTaglib"
contentType="text/html">
<h:messages />
<h:form>
<h:panelGrid columns="2" border="1">
<h:outputText value="Style" style="font-weight: bold" />
<h:outputText value="Output" style="font-weight: bold" />
<h:outputText value="(default)" />
<h:outputText value="#{updatePhoneNumberAction.phoneNumber}">
<o:convertPhoneNumber />
</h:outputText>
<h:outputText value="parentheses" />
<h:outputText value="#{updatePhoneNumberAction.phoneNumber}">
<o:convertPhoneNumber style="parentheses" />
</h:outputText>
<h:outputText value="spaces" />
<h:outputText value="#{updatePhoneNumberAction.phoneNumber}">
<o:convertPhoneNumber style="spaces" />
</h:outputText>
<h:outputText value="dashes" />
<h:outputText value="#{updatePhoneNumberAction.phoneNumber}">
<o:convertPhoneNumber style="dashes" />
</h:outputText>
</h:panelGrid>
<p>
Phone Number:
<h:inputText value="#{updatePhoneNumberAction.phoneNumber}">
<o:convertPhoneNumber style="spaces" />
</h:inputText>
<h:commandButton action="#{updatePhoneNumberAction.update()}"
value="Update" />
</p>
</h:form>
</f:view>
</pre><br />
When we first load the page, we can see our converter in action:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaKM1zm8O-3498fUOLIPEPWZ2ooOHRyuPQl12ic3DLHLoMla7h6_kF_4Ip1awzGjcG29jsEAt0DM2lciTtoIwgDBA4PQsPOEdmKbXviiKHakBGARtAvRoqZLLp24bxPfdB5LvcE0ZpRw/s1600/udpatePhoneNumber+screenshot+1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaKM1zm8O-3498fUOLIPEPWZ2ooOHRyuPQl12ic3DLHLoMla7h6_kF_4Ip1awzGjcG29jsEAt0DM2lciTtoIwgDBA4PQsPOEdmKbXviiKHakBGARtAvRoqZLLp24bxPfdB5LvcE0ZpRw/s1600/udpatePhoneNumber+screenshot+1.png" /></a></div><br />
And since we have our converter on the inputText component, we can see it converter back to a USAPhoneNumber when we add an extension:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho6CIMccarjdvXfJAQwpzdt2AVMDXFxJ4KIlsFWO9U-rOB6_u_EhyujNRgerrZsb9fvXjJg3zlDEFTnnNzsgZwN5imJoJC2Ydp6sxcIxGw5i386CCgod8lJT1qK8_nknkatVW-yyomNA/s1600/udpatePhoneNumber+screenshot+2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho6CIMccarjdvXfJAQwpzdt2AVMDXFxJ4KIlsFWO9U-rOB6_u_EhyujNRgerrZsb9fvXjJg3zlDEFTnnNzsgZwN5imJoJC2Ydp6sxcIxGw5i386CCgod8lJT1qK8_nknkatVW-yyomNA/s320/udpatePhoneNumber+screenshot+2.png" /></a></div><br />
Hopefully, all of this will be a lot easier in future versions of JSF. For those of us stuck on JSF 1.2, though, creating our own converters with attributes can come in handy!<br />
<br />
<link href="http://alexgorbatchev.com/pub/sh/2.1.364/styles/shCore.css" rel="stylesheet" type="text/css"></link> <link href="http://alexgorbatchev.com/pub/sh/2.1.364/styles/shThemeDefault.css" rel="stylesheet" type="text/css"></link> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shCore.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushXml.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushCss.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushJava.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushPhp.js" type="text/javascript">
</script> <script src="http://alexgorbatchev.com/pub/sh/2.1.364/scripts/shBrushJScript.js" type="text/javascript">
</script> <script type="text/javascript">
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.defaults['toolbar'] = true;
SyntaxHighlighter.all();
</script>Jerry Orrhttp://www.blogger.com/profile/06855141821400610431noreply@blogger.com2