<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Carl Sziebert</title>
	
	<link>http://sziebert.net</link>
	<description>is a software engineer with an interest in Spring, Hibernate, Red5 and jQuery development.</description>
	<lastBuildDate>Thu, 29 Jul 2010 20:25:08 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/sziebert" /><feedburner:info uri="sziebert" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Thursday, 11 February 2010</title>
		<link>http://feedproxy.google.com/~r/sziebert/~3/goneML1HTCw/</link>
		<comments>http://sziebert.net/posts/11-02-2010/#comments</comments>
		<pubDate>Thu, 11 Feb 2010 22:35:41 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
				<category><![CDATA[Links]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[ux]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=197</guid>
		<description><![CDATA[<p><a href="http://opensourcemediaframework.com">Open Source Media Framework</a></p>
<p>Open Source Media Framework (OSMF) is an open software framework for building robust, feature-rich video players and applications based on the Adobe® Flash® Platform.</p>
<p><b>Anyone have any experience working with it?</b></p>
<p><a href="http://filamentgroup.com/dwpe/">Designing with Progressive Enhancement</a></p>
<p>Designing with Progressive Enhancement is a practical guide that both explains the principles and benefits of progressive enhancement, and explores detailed examples to teach you how, where, and when to implement specific coding and scripting approaches that embody broadly accessible development practices.</p>
<p><b>I just pre-ordered the book. You should too if you do anything in design or user experience.</b></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/11-02-2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://sziebert.net/posts/11-02-2010/</feedburner:origLink></item>
		<item>
		<title>Wednesday, 10 February 2010</title>
		<link>http://feedproxy.google.com/~r/sziebert/~3/ij3F5MM2kh8/</link>
		<comments>http://sziebert.net/posts/10-02-2010/#comments</comments>
		<pubDate>Wed, 10 Feb 2010 19:22:02 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
				<category><![CDATA[Links]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=182</guid>
		<description><![CDATA[<p><a href="http://perfectionkills.com/javascript-quiz/">Perfection kills &raquo; Javascript quiz</a></p>
<p>&#8220;The quiz mainly focuses on knowledge of scoping, function expressions (and how they differ from function declarations), references, process of variable and function declaration, order of evaluation, and a couple more things like delete operator and object instantiation.&#8221;</p>
<p><b>I missed 3. How about you?</b></p>
<p><a href="http://pixelmatrixdesign.com/uniform/">Uniform</a></p>
<p>&#8220;Uniform masks your standard form controls with custom themed controls. It works in sync with your real form elements to ensure accessibility and compatibility.&#8221;</p>
<p><b>An excellent jQuery plugin for styling forms. It even supports theming, though not through the ThemeRoller.</b></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/10-02-2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://sziebert.net/posts/10-02-2010/</feedburner:origLink></item>
		<item>
		<title>_.js</title>
		<link>http://feedproxy.google.com/~r/sziebert/~3/3cCH7xxFXs0/</link>
		<comments>http://sziebert.net/posts/underscore-js/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 15:41:27 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[underscore.js]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=175</guid>
		<description><![CDATA[<p><a href="http://documentcloud.github.com/underscore/">Underscore.js</a> is self described as &#8220;a utility-belt library for Javascript that provides a lot of the functional programming that you would expect in <a href="http://prototypejs.org/">Prototype.js</a>, but without extending any of the built-in Javascript objects.&#8221; The usefulness of this little library becomes apparent after reading though the documentation. I&#8217;ve already integrated it into a couple of projects where I needed a robust, yet lightweight core.</p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/underscore-js/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://sziebert.net/posts/underscore-js/</feedburner:origLink></item>
		<item>
		<title>Interaction prototyping with IxEdit</title>
		<link>http://feedproxy.google.com/~r/sziebert/~3/zKJLQrI5FEE/</link>
		<comments>http://sziebert.net/posts/interaction-prototyping-with-ixedit/#comments</comments>
		<pubDate>Thu, 22 Oct 2009 13:49:10 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[ixedit]]></category>
		<category><![CDATA[prototyping]]></category>
		<category><![CDATA[ux engineering]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=171</guid>
		<description><![CDATA[<p><a href="http://www.ixedit.com/">IxEdit</a> is a superb tool for on-the-fly prototyping of interactive functionality with <a href="http://jquery.com/">jQuery</a>.  It is embedded directly in the html you are working with, is lightweight, and actually produces readable/usable code. If you do anything with jQuery, you&#8217;ll want to give IxEdit a look.</p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/interaction-prototyping-with-ixedit/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://sziebert.net/posts/interaction-prototyping-with-ixedit/</feedburner:origLink></item>
		<item>
		<title>GrepCode</title>
		<link>http://feedproxy.google.com/~r/sziebert/~3/uKhlj9xKZlU/</link>
		<comments>http://sziebert.net/posts/grepcode/#comments</comments>
		<pubDate>Wed, 21 Oct 2009 15:57:01 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=169</guid>
		<description><![CDATA[<p><a title="GrepCode" href="http://grepcode.com/">GrepCode</a> is an extremely cool code searching tool for open source Java.  The most useful feature, in my opinion, is the ability to find code responsible for a specific stack trace.  While they have a few usability issues to iron out, this is definitely something worth adding to your developer toolbox.</p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/grepcode/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://sziebert.net/posts/grepcode/</feedburner:origLink></item>
		<item>
		<title>Using Bcrypt with Spring Security</title>
		<link>http://feedproxy.google.com/~r/sziebert/~3/1jlb17fPYE0/</link>
		<comments>http://sziebert.net/posts/using-bcrypt-with-spring-security/#comments</comments>
		<pubDate>Sun, 10 May 2009 00:03:36 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
				<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Spring Framework]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[BCrypt]]></category>
		<category><![CDATA[Spring MVC]]></category>
		<category><![CDATA[Spring Security]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=110</guid>
		<description><![CDATA[<p>Password security is a <a href="http://www.codinghorror.com/blog/archives/001263.html">popular</a> <a href="http://blog.moertel.com/articles/2006/12/15/never-store-passwords-in-a-database">topic</a>. The most basic tenant of password security is to have no password at all.  Wait, what? That&#8217;s right, no password should be stored in your database, ever. Instead, store it as a hash, along with the salt, and throw the original password away. Ask 10 different developers, and I&#8217;ll bet that MD5 would be offered as the most popular solution for this problem. Though, if you&#8217;ve explored the linked content, you&#8217;ll have undoubtedly noticed that <a href="http://bcrypt.sourceforge.net/">Bcrypt</a> is mentioned more than a few times.  </p>
<blockquote><p>&#8220;Bcrypt is a cross platform file encryption utility. Encrypted files are portable across all supported operating systems and processors. Passphrases must be between 8 and 56 characters and are hashed internally to a 448 bit key. However, all characters supplied are significant. The stronger your passphrase, the more secure your data.&#8221;</p></blockquote>
<p>For us Java developers, there&#8217;s <a href="http://www.mindrot.org/projects/jBCrypt/">jBCrypt</a>. It is an &#8220;implementation of OpenBSD&#8217;s Blowfish password hashing code&#8221; and offers a rather simple <acronym title="Application Programming Interface">API</acronym>.  A quick web search yields a bit of information on using <a href="http://stackoverflow.com/questions/622732/what-to-use-for-password-hashing-any-reason-not-to-use-jbcrypt">jBCrypt itself</a>, but nothing on integrating it with the Spring Framework.  Given that this is a topic of interest to me, I&#8217;ve put together a simple, yet comprehensive example web application to demonstrate an integration of jBCrypt, Spring MVC, Spring Security and Hibernate for hashing user passwords.  There are three areas I&#8217;ve focused on in this example, user creation, user authentication and changing the user&#8217;s password.<!--more--></p>
<p>Unlike other solutions, jBCrypt is surprisingly easy to use.  When a new user registers for our simple application, the password is hashed using <tt>BCrypt.hashpw(rawPass, salt)</tt>.  You, the developer, are given a choice of providing a salt or generating a random salt with <tt>BCrypt.gensalt()</tt>.  I&#8217;ve chosen to use a random salt for each hash, increasing the strength of the solution.  Here&#8217;s a look at the code responsible for creating the new <tt>User</tt> object.</p>
<p><strong>JoinController.java</strong></p>
<pre class="brush: java;">
@Controller
public class JoinController {
    ...
    @RequestMapping(value = &quot;/join.do&quot;, method = RequestMethod.POST)
    public String processSubmit(@ModelAttribute(&quot;form&quot;) JoinForm form, BindingResult result) {
        logger.debug(&quot;Processing join form.&quot;);
        new JoinFormValidator().validate(form, result);
        if (!result.hasErrors()) {
            User user = new User(
                    form.getUsername(),
                    BCrypt.hashpw(form.getPassword(), BCrypt.gensalt()),
                    form.getEmail());
            service.create(user);
            return &quot;join-success&quot;;
        }
        return &quot;join&quot;;
    }
    ...
}
</pre>
<p>The astute observer might note that I could have used a Hibernate <tt>Interceptor</tt> to hash the password when the <tt>User</tt> is inserted into the database.  And while that is a valid solution, I prefer to get rid of the original password sooner and keep the hashing routine along side the <tt>User</tt> creation code.</p>
<p>User authentication with Spring Security needs to use a <tt>PasswordEncoder</tt> implementation to hash and validate the supplied password.  This is straight forward to do as is demonstrated in the example application.</p>
<p><strong>BCryptPasswordEncoder.java</strong></p>
<pre class="brush: java;">
public class BCryptPasswordEncoder implements PasswordEncoder {

    public String encodePassword(String rawPass, Object salt) throws DataAccessException {
        logger.debug(&quot;Encoding password.&quot;);
        return BCrypt.hashpw(rawPass, BCrypt.gensalt());
    }

    public boolean isPasswordValid(String encPass, String rawPass, Object salt) throws DataAccessException {
        logger.debug(&quot;Validating password.&quot;);
        return BCrypt.checkpw(rawPass, encPass);
    }
}
</pre>
<p>As you can see, there really isn&#8217;t much to this.  You&#8217;ll need to instruct Spring Security to use your <tt>PasswordEncoder</tt> by adding a bean definition and dependency to your context configuration file.</p>
<p><strong>spring-security.xml</strong></p>
<pre class="brush: xml;">
    &lt;authentication-provider user-service-ref=&quot;userService&quot;&gt;
        &lt;password-encoder ref=&quot;passwordEncoder&quot;/&gt;
    &lt;/authentication-provider&gt;

    &lt;beans:bean id=&quot;passwordEncoder&quot; class=&quot;net.sziebert.tutorials.security.BCryptPasswordEncoder&quot;/&gt;
</pre>
<p>Changing the user&#8217;s password is no different, though it does have two parts to get it right.  Because we require the user to supply their original password before updating it, we need to insure the input is correct.  </p>
<p><strong>ChangePasswordFormValidator.java</strong></p>
<pre class="brush: java;">
public class ChangePasswordFormValidator implements Validator {
    ...
    public void validate(Object obj, Errors errors) {
        logger.debug(&quot;Validating change password form.&quot;);
        ChangePasswordForm form = (ChangePasswordForm) obj;
        ...
        // Insure the specified original password actually matches the performer's current password.
        if (isNotBlank(form.getPassword())) {
            if (!BCrypt.checkpw(form.getOriginal(), user.getPassword())) {
                errors.rejectValue(&quot;original&quot;, &quot;error.original.password.mismatch&quot;);
            }
        }
    }
}
</pre>
<p>Once the original validates correctly, we can then update the database with the a new hash.  Like the previous examples, this is trivial to accomplish.</p>
<p><strong>ChangePasswordController.java</strong></p>
<pre class="brush: java;">
@Controller
public class ChangePasswordController {
    ...
    @RequestMapping(value = &quot;/password.do&quot;, method = POST)
    public String processSubmit(HttpServletRequest request,
                                @ModelAttribute(&quot;form&quot;) ChangePasswordForm form,
                                BindingResult result) {
        logger.debug(&quot;Processing change password form.&quot;);
        User user = service.findByUsername(getCurrentUsername());
        new ChangePasswordFormValidator(user).validate(form, result);
        if (!result.hasErrors()) {
            user.setPassword(BCrypt.hashpw(form.getPassword(), BCrypt.gensalt()));
            service.update(user);
            request.getSession().setAttribute(&quot;message&quot;, &quot;You have successfully changed your password.&quot;);
            return &quot;redirect:/home.do&quot;;
        }
        return &quot;change-password&quot;;
    }
    ...
}
</pre>
<p>As with all of my posts, I invite you to download the example application and give it a try.  Make sure that you&#8217;ve got all of the dependencies and have compiled the source by running <tt>ant compile</tt>.  Let me know if you&#8217;ve got questions or feedback.</p>
<p><strong>The example source code for this post can be downloaded <a href="http://sziebert.net/software/examples/BCrypt+SpringSecurity.zip">here</a>.</strong></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/using-bcrypt-with-spring-security/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://sziebert.net/posts/using-bcrypt-with-spring-security/</feedburner:origLink></item>
		<item>
		<title>Server-side stream recording example updated</title>
		<link>http://feedproxy.google.com/~r/sziebert/~3/EmnvSXyvqXU/</link>
		<comments>http://sziebert.net/posts/server-side-stream-recording-updated/#comments</comments>
		<pubDate>Tue, 14 Apr 2009 04:08:32 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
				<category><![CDATA[ActionScript]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Red5]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=92</guid>
		<description><![CDATA[<p>With this being my most popular blog topic, I felt the time has come for a little update. (You can catch up on the original <a href="http://sziebert.net/posts/server-side-stream-recording-with-red5/">here</a>.)  Frankly, there&#8217;s not much too it.  The server-side code didn&#8217;t change much, just an update to take advantage of the built-in logging support of Red5.  Both clients have been completely rewritten using ActionScript 3. (I know, it&#8217;s about time.) <!--more--></p>
<p>Recording the stream on the server takes one simple line as displayed here:</p>
<p><strong>StreamManager.java</strong></p>
<pre class="brush: java;">
ClientBroadcastStream stream = (ClientBroadcastStream) app.getBroadcastStream(conn.getScope(), &quot;hostStream&quot;);
try {
	// Save the stream to disk.
	stream.saveAs(streamName, false);
} catch (Exception e) {
	logger.error(&quot;Error while saving stream: {}&quot;, streamName);
}
</pre>
<p>The only button in the broadcast application starts and stops the recording session.  The <tt>click</tt> handler does all the work:</p>
<p><strong>Broadcast.as</strong></p>
<pre class="brush: as3;">
private function onClick(event:MouseEvent):void {
	var button:Button = event.target as Button;
	// Record the stream by triggering a server event.
	if (button.label == &quot;Record&quot;) {
		// Tell the remote server to start recording.
		runtime.conn.call(&quot;streamManager.recordShow&quot;, null);
		// Re-label the button.
		button.label = &quot;Stop&quot;;
	// Stop recording the stream.
	} else if (button.label == &quot;Stop&quot;) {
		// Tell the remote server to stop recording.
		runtime.conn.call(&quot;streamManager.stopRecordingShow&quot;, null);
		// Re-label the button.
		button.label = &quot;Record&quot;;
	}
}
</pre>
<p>Like I said, not much to it.  But there&#8217;s a lot of power wrapped up in this little piece of functionality.  </p>
<p><strong>Grab the source code for this tutorial <a href="http://garagetech.googlecode.com/files/Recorder.zip">here</a>.</strong> The example code was updated to be compatible with Red5 0.9.1 on July 29, 2010.</p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/server-side-stream-recording-updated/feed/</wfw:commentRss>
		<slash:comments>43</slash:comments>
		<feedburner:origLink>http://sziebert.net/posts/server-side-stream-recording-updated/</feedburner:origLink></item>
		<item>
		<title>jQuery Transmit file upload plugin updated</title>
		<link>http://feedproxy.google.com/~r/sziebert/~3/JoR_LGpdcdc/</link>
		<comments>http://sziebert.net/posts/jquery-transmit-file-upload-plugin-updated/#comments</comments>
		<pubDate>Fri, 13 Mar 2009 22:03:47 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
				<category><![CDATA[ActionScript]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=80</guid>
		<description><![CDATA[<p>Having finally gotten a few hours to myself, I&#8217;ve updated the jquery-transmit file upload plugin to support Flash 10.  Because of the security restrictions added in the most recent revision of the flash browser plugin, the calls to trigger the file selection dialog needed to occur in the SWF itself.  To achieve this, the SWF is placed on a layer above the links triggering the dialog.  You should be able to successfully edit the HTML to your liking without much consequence.  Though, you should be careful not to rename any of the ids or classes.  The plugin relies on them to place the SWF and resize it as necessary. As with the initial release, the plugin should be considered a work in progress and is not yet suitable for a production environment. Hopefully, this fact won&#8217;t deter you from giving the plugin a try.  Source and downloads are available at <a href="http://code.google.com/p/jquery-transmit/">googlecode</a>.  As always, constructive feedback is very much appreciated.</p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/jquery-transmit-file-upload-plugin-updated/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://sziebert.net/posts/jquery-transmit-file-upload-plugin-updated/</feedburner:origLink></item>
		<item>
		<title>Do you Xuggle?</title>
		<link>http://feedproxy.google.com/~r/sziebert/~3/_e20vypA61c/</link>
		<comments>http://sziebert.net/posts/do-you-xuggle/#comments</comments>
		<pubDate>Thu, 19 Feb 2009 17:36:27 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Red5]]></category>
		<category><![CDATA[Xuggle]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=65</guid>
		<description><![CDATA[<p>If you are a <a href="http://osflash.org/red5">Red5</a> or <a href="http://www.ffmpeg.org/">FFmpeg</a> user, then you should be very interested in what <a href="http://www.xuggle.com/">Xuggle</a> is working on.  Their current project, <a href="http://www.xuggle.com/xuggler/">Xuggler</a>, is a welcome addition to my <abbr title="Rich Internet Application">RIA</abbr> toolbox, and should be a mainstay of yours as well. From their website: </p>
<blockquote><p>&#8220;The Xuggler is a free and open-source library for Java or C++ developers that allows you to decode, manipulate, and encode (almost) any type of video file in near real time. It is for programmers who want to add video processing support to their products.&#8221;</p></blockquote>
<p>What does this mean for me, you ask?<!--more--> Let me provide some history for you on my own experiences.  When I started out with streaming media back in 2004, there was only one decent way to build applications.  That was using <abbr title="Server-side ActionScript">SSAS</abbr> on Flash Communications Server 1.5.  (For those of you into fact checking, Red5 was around back then, but was still very much in it&#8217;s infancy.)  To accomplish something like the functionality available in Xuggler was next to impossible.  Transforming a stream wasn&#8217;t exact an &#8220;on-the-fly&#8221; activity.  It meant installing FFmpeg, writing some sort of wrapper around it and then invoking it as a post-process after the stream had finished recording to disk.  Even a relatively trivial task like pulling screenshots out of a live stream required a huge amount of overhead and in-depth knowledge of the FFmpeg internals.  Xuggler is aimed squarely at making this sort of thing much simpler.  Don&#8217;t believe me?  Give their demo a look:<br />
<br/><br />
<object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/L7dk4s4ronk&#038;hl=en&#038;fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/L7dk4s4ronk&#038;hl=en&#038;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object><br />
<br/></p>
<p>In addition to open-sourcing the project, Xuggle also provides an added benefit to Red5 developers in the form of a <a href="http://www.xuggle.com/xuggler/red5/">native adapter</a> to create stream mash-ups in near real time. If that isn&#8217;t enough to convince you to check out Xuggler, then I&#8217;m not sure what is.  Details on the project can be found <a href="http://www.xuggle.com/xuggler/">here</a>.  The source code can be checked out from Subversion <a href="http://code.google.com/p/xuggle/">here</a>.</p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/do-you-xuggle/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://sziebert.net/posts/do-you-xuggle/</feedburner:origLink></item>
		<item>
		<title>Red5 + Hibernate Revisited</title>
		<link>http://feedproxy.google.com/~r/sziebert/~3/JKqICEp-dvg/</link>
		<comments>http://sziebert.net/posts/red5-hibernate-revisited/#comments</comments>
		<pubDate>Fri, 30 Jan 2009 22:13:06 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
				<category><![CDATA[Flash]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Red5]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Spring Framework]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=39</guid>
		<description><![CDATA[<p>It&#8217;s hard to believe that I wrote the first version of this tutorial almost a year and a half ago.  That&#8217;s too long to wait for an update in my opinion and is much needed in this case.  My apologies for not tending to the garden sooner. While the <a href="http://sziebert.net/posts/red5-hibernate/">original article</a> illustrated a simple method for integrating Red5<a class="sup" href="#red5">[1]</a> and Hibernate<a class="sup" href="#hibernate">[2]</a>, by today&#8217;s standards it&#8217;s design is overly verbose and somewhat out of fashion. Not to mention the 3 major components used in this tutorial have all gone through major revisions. The primary goal for this iteration was simplification of the code as well as the XML configuration elements and results in a smaller code footprint.  This is a big win in my book.<!--more--></p>
<p><strong>*Note</strong>: If you are not familiar with my first post on this topic, please <a href="http://sziebert.net/posts/red5-hibernate/">give it a read</a> before continuing here.</p>
<p>Getting started, the only item left untouched by the refactoring is the <tt>User</tt> object.  Given that I originally defined the class using the Hibernate annotations there is nothing to change other than to use the annotation based <tt>SessionFactory</tt> by default.  I should note that the Hibernate mapping (HBM) file for the <tt>User</tt> object no longer exists in the source tree.</p>
<p><strong>User.java</strong></p>
<pre class="brush: java;">
@Entity
@Table(name = &quot;users&quot;)
public class User {

    @Id
    @GeneratedValue
    @Column(name = &quot;id&quot;, nullable = false)
    private Long id;

    @Column(name = &quot;user_name&quot;, nullable = false, length = 32, unique = true)
    private String userName;

    @Column(name = &quot;password&quot;, nullable = false)
    private String password;

    @Column(name = &quot;first_name&quot;, length = 64)
    private String firstName;

    @Column(name = &quot;last_name&quot;, length = 64)
    private String lastName;

    @Column(name = &quot;email&quot;, nullable = false)
    private String email;

    ...
}
</pre>
<p><tt>HibernateApplicationDAO</tt> has been given a new name and is now <tt>HibernateApplicationRepository</tt>.  This is one of the biggest changes here and removes the dependency on Spring&#8217;s <tt>HibernateTemplate</tt>.  <tt>HibernateTemplate</tt> was originally created to work around the limitations of Hibernate 2&#8242;s usage of checked exceptions.  Because Hibernate now uses unchecked runtime exceptions, it is no longer necessary.  Injection of the <tt>SessionFactory</tt> into the repository object gives us direct access to the current Hibernate<tt>Session</tt>. The <tt>@Repository</tt> annotation has been added to support transactions and persistence exception translation.</p>
<p><strong>HibernateApplicationRepository.java</strong></p>
<pre class="brush: java;">
@Repository
public class HibernateApplicationRepository implements ApplicationRepository {

    private static final Logger logger = Red5LoggerFactory.getLogger(HibernateApplicationRepository.class, &quot;hibernate&quot;);

    private SessionFactory sessionFactory;

    public User getUser(String user, String pass) {
        logger.debug(&quot;Retrieving user from the database.&quot;);
        // Ask Hibernate to query for the user based upon the specified user/pass.
        Criteria crit = sessionFactory.getCurrentSession().createCriteria(User.class);
        crit.add(Restrictions.eq(&quot;userName&quot;, user));
        crit.add(Restrictions.eq(&quot;password&quot;, pass));
        User u = (User) crit.uniqueResult();
        // Insure that we got something back from Hibernate.
        if (null == u) {
            logger.warn(&quot;User does not exist for credentials: {}/{}&quot;, user, pass);
            throw new ObjectRetrievalFailureException(User.class, user);
        }
        // Return the results.
        return u;
    }

    @Required
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
}
</pre>
<p><tt>ApplicationServiceImpl</tt> is now annotated with the <tt>@Service</tt> and <tt>@Transactional</tt> annotations. With these annotations, we no longer need to proxy <tt>ApplicationServiceImpl</tt> and can eliminate several lines of XML in the configuration file while maintaining full transaction support.</p>
<p><strong>ApplicationServiceImpl.java</strong></p>
<pre class="brush: java;">
@Service
@Transactional
public class ApplicationServiceImpl implements ApplicationService {

    private static final Logger logger = Red5LoggerFactory.getLogger(ApplicationServiceImpl.class, &quot;hibernate&quot;);

    private ApplicationRepository repository;

    @Transactional(readOnly = true)
    public User getUser(String user, String pass) throws ServiceException {
        logger.debug(&quot;Looking up user for user/pass of: {}/{}&quot;, user, pass);
        try {
            // Return the result of the data access call.
            return repository.getUser(user, pass);
        }
        catch (Exception e) {
            logger.error(&quot;Could not load user with credentials: {}/{}&quot;, user, pass);
            throw new ServiceException(&quot;Could not load user!&quot;, e);
		}
	}

    @Required
    public void setApplicationRepository(ApplicationRepository repository) {
        this.repository = repository;
    }
}
</pre>
<p>As you can see from the following bean declaration, we&#8217;ve cut down on the XML configuration significantly by taking advantage of these annotations.</p>
<p><strong>red5-web.xml</strong></p>
<pre class="brush: xml;">
    &lt;tx:annotation-driven/&gt;

    &lt;bean id=&quot;transactionManager&quot; class=&quot;org.springframework.orm.hibernate3.HibernateTransactionManager&quot;&gt;
        &lt;property name=&quot;sessionFactory&quot; ref=&quot;sessionFactory&quot;/&gt;
    &lt;/bean&gt;

    &lt;bean id=&quot;applicationRepository&quot; class=&quot;net.sziebert.tutorials.dao.hibernate.HibernateApplicationRepository&quot;&gt;
        &lt;property name=&quot;sessionFactory&quot; ref=&quot;sessionFactory&quot;/&gt;
    &lt;/bean&gt;

    &lt;bean id=&quot;applicationService&quot; class=&quot;net.sziebert.tutorials.service.impl.ApplicationServiceImpl&quot;&gt;
        &lt;property name=&quot;applicationRepository&quot; ref=&quot;applicationRepository&quot;/&gt;
    &lt;/bean&gt;
</pre>
<p>For the sake of direct comparison, here is the original bean declaration:</p>
<p><strong>red5-web.xml</strong></p>
<pre class="brush: xml;">
    &lt;bean id=&quot;transactionManager&quot; class=&quot;org.springframework.orm.hibernate3.HibernateTransactionManager&quot;&gt;
        &lt;property name=&quot;sessionFactory&quot; ref=&quot;sessionFactory&quot; /&gt;
    &lt;/bean&gt;

    &lt;bean id=&quot;txProxyTemplate&quot; abstract=&quot;true&quot; class=&quot;org.springframework.transaction.interceptor.TransactionProxyFactoryBean&quot;&gt;
        &lt;property name=&quot;transactionManager&quot;&gt;
            &lt;ref local=&quot;transactionManager&quot; /&gt;
        &lt;/property&gt;
        &lt;property name=&quot;transactionAttributes&quot;&gt;
            &lt;props&gt;
                &lt;prop key=&quot;get*&quot;&gt;PROPAGATION_REQUIRED,readOnly&lt;/prop&gt;
                &lt;prop key=&quot;save*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;
                &lt;prop key=&quot;update*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;
                &lt;prop key=&quot;delete*&quot;&gt;PROPAGATION_REQUIRED&lt;/prop&gt;
            &lt;/props&gt;
        &lt;/property&gt;
    &lt;/bean&gt;

    &lt;bean id=&quot;applicationDAO&quot; class=&quot;net.sziebert.red5.adapter.dao.hibernate.HibernateApplicationDAO&quot;&gt;
        &lt;property name=&quot;hibernateTemplate&quot; ref=&quot;hibernateTemplate&quot; /&gt;
    &lt;/bean&gt;

    &lt;bean id=&quot;applicationService&quot; parent=&quot;txProxyTemplate&quot;&gt;
        &lt;property name=&quot;target&quot;&gt;
            &lt;bean class=&quot;net.sziebert.red5.adapter.service.impl.ApplicationServiceImpl&quot;&gt;
                &lt;property name=&quot;applicationDAO&quot; ref=&quot;applicationDAO&quot; /&gt;
            &lt;/bean&gt;
        &lt;/property&gt;
    &lt;/bean&gt;
</pre>
<p>All classes now use the improved Red5 logging support which is backed by <a href="http://www.slf4j.org/">SLF4J</a> and <a href="http://logback.qos.ch/">Logback</a> by default.  Here is an example from the <tt>ApplicationAdapter</tt> subclass:</p>
<p><strong>Application.java</strong></p>
<pre class="brush: java;">
public class Application extends ApplicationAdapter {

    private static final Logger logger = Red5LoggerFactory.getLogger(Application.class, &quot;hibernate&quot;);

    private ApplicationService service;

    /* ----- ApplicationAdapter delegate methods ----- */

    @Override
    public boolean roomConnect(IConnection conn, Object[] params) {
        logger.debug(&quot;New connection attempt from {}...&quot;, conn.getRemoteAddress());
        // Parse the user/pass out of the connection parameters
        String userName = (String) params[0];
        String password = (String) params[1];
        // Get the User object for this connection
        User user = null;
        // Insure that we have received the proper set of parameters.
        if (isNotBlank(userName) &amp;&amp;
                isNotBlank(password)) {
            user = authenticate(userName, password);
        }
        // If we got a valid user object, then allow the connection. Otherwise,
        // the user could not be found or something bad happened. In either
        // case, we do not want to allow the connection.
        return user != null &amp;&amp; super.roomConnect(conn, params);
    }

    ...
}
</pre>
<p>The flash client code has been rewritten entirely in ActionScript 3 and was reduced down to a single class for the entire application.  For those of you following along with the source, you&#8217;ll note that there are actually 2 classes.  The second one is a simple dynamic class used to store runtime related resources and could be easily removed from the implementation.  It was a design decision on my part to keep it.  ActionScript 3 is much more object-oriented than it&#8217;s predecessor and leverages the new keyword for constructing components.</p>
<p><strong>Hibernate.as</strong></p>
<pre class="brush: as3;">
package net.sziebert.tutorials {

	import com.adobe.crypto.MD5;

	import fl.controls.Button;
	import fl.controls.Label;
	import fl.controls.TextArea;
	import fl.controls.TextInput;
	import fl.managers.StyleManager;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.NetStatusEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.NetConnection;
	import flash.net.ObjectEncoding;
	import flash.net.registerClassAlias;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;

	import net.sziebert.tutorials.Runtime;

	public class Hibernate extends Sprite {

		private var connect:Button;
		private var pass:TextInput;
		private var passLbl:Label;
		private var runtime:Runtime;
		private var textArea:TextArea;
		private var user:TextInput;
		private var userLbl:Label;

		public function Hibernate():void {
			trace(&quot;Starting Hibernate application...&quot;);
			runtime = Runtime.getInstance();
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.addEventListener(Event.RESIZE, onResize);
			createChildren();
		}

		/* ----- Utility functions ----- */

		private function createChildren():void {
			// Create the username label.
			userLbl = new Label();
			userLbl.text = &quot;Username:&quot;;
			userLbl.autoSize = TextFieldAutoSize.LEFT;
			addChild(userLbl);
			// Create the username input field.
			user = new TextInput();
			user.maxChars = 255;
			user.restrict = &quot;A-Za-z 0-9:;()|.,?!$&amp;*{}[]+=_-'&quot;&quot;;
			addChild(user);
			// Create the password label,
			passLbl = new Label();
			passLbl.text = &quot;Password:&quot;;
			passLbl.autoSize = TextFieldAutoSize.LEFT;
			addChild(passLbl);
			// Create the password input field.
			pass = new TextInput();
			pass.maxChars = 255;
			pass.displayAsPassword = true;
			addChild(pass);
			// Create the connect button.
			connect = new Button();
			connect.label = &quot;Connect&quot;;
			connect.addEventListener(MouseEvent.CLICK, onClick);
			addChild(connect);
			// Create the text area to display the log information.
			textArea = new TextArea();
			textArea.editable = false;
			textArea.wordWrap = true;
			addChild(textArea);
			// Remove the avatar.
			removeChildAt(0);
			// Size the elements.
			setSize(stage.stageWidth, stage.stageHeight);
		}

		private function setSize(w:Number, h:Number):void {
			// Move and size the username components
			userLbl.move(18, 18);
			//userLabel.setSize(50, 22);
			user.move(96, 18);
			user.setSize((w - 226), 22);
			// Move and size the password components
			passLbl.move(18, 50);
			//passLabel.setSize(50, 22);
			pass.move(96, 50);
			pass.setSize((w - 226), 22);
			// Move and size the connect button
			connect.move(w - 118, 18);
			connect.setSize(100, 54);
			// Move and size the textarea
			textArea.move(18, 82);
			textArea.setSize((w - 36), (h - 100));
		}

		private function initConnection(username:String, password:String):void {
			if (username == &quot;&quot; || password == &quot;&quot;) {
				throw new Error(&quot;You must enter a valid username and/or password.&quot;);
			}
			// Create the new connection object.
			runtime.conn = new NetConnection();
			runtime.conn.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
			runtime.conn.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
			log(&quot;Connecting to Red5...&quot;);
			runtime.conn.connect(&quot;rtmp://localhost/hibernate/test&quot;, username, MD5.hash(password));
		}

		private function log(msg:String):void {
			// Update the chat window with the message
			textArea.text += (msg + &quot;n&quot;);
			textArea.verticalScrollPosition = textArea.maxVerticalScrollPosition;
		}

		/* ----- Event handlers ----- */

		private function onResize(event:Event):void {
			setSize(stage.stageWidth, stage.stageHeight);
		}

		private function onClick(event:MouseEvent):void {
			var button:Button = event.target as Button;
			// We are currently connected, so disconnect.
			if (runtime.conn &amp;&amp; runtime.conn.connected) {
				runtime.conn.close();
				return;
			}
			try {
				// Initialize the connection
				initConnection(user.text, pass.text);
			} catch (err:Error) {
				// Otherwise we need to show an alert indicating the need for proper user input.
				log(&quot;Error: You must enter a valid username and/or password.&quot;);
			}
		}

		private function onNetStatus(event:NetStatusEvent):void {
			trace(&quot;onNetStatus: &quot; + event.info.code);
			switch (event.info.code) {
			        case &quot;NetConnection.Connect.Success&quot;:
					log(&quot;Connection attempt successful.&quot;);
					connect.label = &quot;Disconnect&quot;;
                                        break;
				case &quot;NetConnection.Connect.Rejected&quot;:
					log(&quot;Connection attempt rejected.&quot;);
					break;
				case &quot;NetConnection.Connect.Closed&quot;:
					log(&quot;Connection closed.&quot;);
					connect.label = &quot;Connect&quot;;
					break;
				case &quot;NetConnection.Connect.Failed&quot;:
					log(&quot;Connection failure.&quot;);
					break;
		        }
		}

		private function onSecurityError(event:SecurityErrorEvent):void {
        		trace(&quot;onSecurityError: &quot; + event);
        	}
	}
}
</pre>
<p>Lastly, the tutorial now relies upon Ant and Ivy to define and retrieve the necessary dependencies. There&#8217;s nothing terribly magical about it, the build script should take care of everything for you. Keep in mind that the Red5 JAR dependency is pulled directly from the continuous integration server and should be up to date with the latest found in the Subversion repository at <a href="http://code.google.com/p/red5/">googlecode</a>.  If you aren&#8217;t running on the latest from trunk, you should strongly consider replacing this JAR with the one found in your Red5 install.  </p>
<p><strong>ivy.xml</strong></p>
<pre class="brush: xml;">
&lt;ivy-module version=&quot;2.0&quot;
            xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
            xsi:noNamespaceSchemaLocation=&quot;http://ant.apache.org/ivy/schemas/ivy.xsd&quot;&gt;
    &lt;info organisation=&quot;garagetech&quot; module=&quot;tutorials&quot;/&gt;
    &lt;configurations defaultconfmapping=&quot;default-&gt;*&quot;&gt;
        &lt;conf name=&quot;compile&quot;/&gt;
        &lt;conf name=&quot;default&quot;/&gt;
        &lt;conf name=&quot;test&quot; extends=&quot;default&quot; description=&quot;Unit testing dependencies.&quot;/&gt;
    &lt;/configurations&gt;
    &lt;dependencies&gt;
        &lt;dependency name=&quot;commons-dbcp&quot; org=&quot;commons&quot; rev=&quot;1.2.2&quot;/&gt;
        &lt;dependency name=&quot;commons-lang&quot; org=&quot;commons&quot; rev=&quot;2.4&quot; conf=&quot;compile-&gt;*&quot;/&gt;
        &lt;dependency name=&quot;dom4j&quot; rev=&quot;1.6.1&quot;/&gt;
        &lt;dependency name=&quot;ejb3-persistence&quot; rev=&quot;&quot; conf=&quot;compile-&gt;*&quot;/&gt;
        &lt;dependency name=&quot;hibernate-annotations&quot; org=&quot;hibernate&quot; rev=&quot;3.4.0&quot;/&gt;
        &lt;dependency name=&quot;hibernate-commons-annotations&quot; org=&quot;hibernate&quot; rev=&quot;3.4.0&quot;/&gt;
        &lt;dependency name=&quot;hibernate-entitymanager&quot; org=&quot;hibernate&quot; rev=&quot;3.4.0&quot;/&gt;
        &lt;dependency name=&quot;hibernate-validator&quot; org=&quot;hibernate&quot; rev=&quot;3.1.0&quot;/&gt;
        &lt;dependency name=&quot;hibernate&quot; org=&quot;hibernate&quot; rev=&quot;3.3.1&quot;/&gt;
        &lt;dependency name=&quot;javassist&quot; rev=&quot;3.4&quot;/&gt;
        &lt;dependency name=&quot;mysql-connector-java&quot; rev=&quot;5.0.6-bin&quot;/&gt;
        &lt;dependency name=&quot;red5&quot; rev=&quot;&quot; changing=&quot;true&quot; conf=&quot;compile-&gt;*&quot;/&gt;
        &lt;dependency name=&quot;slf4j-api&quot; rev=&quot;1.5.6&quot; conf=&quot;compile-&gt;*&quot;/&gt;
        &lt;dependency name=&quot;spring-aop&quot; org=&quot;spring&quot; rev=&quot;2.5.6&quot; conf=&quot;compile-&gt;*&quot;/&gt;
        &lt;dependency name=&quot;spring-beans&quot; org=&quot;spring&quot; rev=&quot;2.5.6&quot; conf=&quot;compile-&gt;*&quot;/&gt;
        &lt;dependency name=&quot;spring-context&quot; org=&quot;spring&quot; rev=&quot;2.5.6&quot; conf=&quot;compile-&gt;*&quot;/&gt;
        &lt;dependency name=&quot;spring-core&quot; org=&quot;spring&quot; rev=&quot;2.5.6&quot; conf=&quot;compile-&gt;*&quot;/&gt;
        &lt;dependency name=&quot;spring-jdbc&quot; org=&quot;spring&quot; rev=&quot;2.5.6&quot;/&gt;
        &lt;dependency name=&quot;spring-orm&quot; org=&quot;spring&quot; rev=&quot;2.5.6&quot;/&gt;
        &lt;dependency name=&quot;spring-tx&quot; org=&quot;spring&quot; rev=&quot;2.5.6&quot;/&gt;
    &lt;/dependencies&gt;
&lt;/ivy-module&gt;
</pre>
<p>That covers the significant changes to the tutorial code.  As with the first version, you’ll need to configure MySQL to allow Red5 to talk to it. (Notes on this can be found in the README file with the examples.) You’ll also need to add your user data to the tables once Hibernate has generated the schema.</p>
<p><strong>The example source code for this post can be downloaded <a href="http://garagetech.googlecode.com/files/Red5%2BHibernate.zip">here</a>.</strong></p>
<p>1. <a name="red5" href="http://osflash.org/red5">http://osflash.org/red5</a>  For those that aren&#8217;t up on Red5, it is a robust Flash Media Server alternative written entirely in Java that supports multi-user video chat, video streaming and real-time, multi-player gaming.</p>
<p>2. <a name="hibernate" href="http://hibernate.org">http://hibernate.org</a>  Hibernate lets you develop persistent classes following object-oriented idiom &#8211; including association, inheritance, polymorphism, composition, and collections. It allows you to express queries in its own portable SQL extension (HQL), as well as in native SQL.</p>
<p>3. <a name="spring" href="http://springframework.org">http://springframework.org</a> Spring is a layered Java/JEE application framework founded on the simple concepts that any tool should be a pleasure to use, that your application code should not depend on Spring APIs and that it should not compete with existing solutions, but should foster integration.</p>
<p>4. <a name="mysql" href="http://mysql.com">http://mysql.com</a>  The MySQL database has become the world&#8217;s most popular open source database because of its consistent fast performance, high reliability and ease of use.</p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/red5-hibernate-revisited/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		<feedburner:origLink>http://sziebert.net/posts/red5-hibernate-revisited/</feedburner:origLink></item>
	</channel>
</rss>
