<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><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: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>
	<pubDate>Tue, 04 Nov 2008 18:14:26 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/sziebert" type="application/rss+xml" /><item>
		<title>Go vote.  Now.</title>
		<link>http://feeds.feedburner.com/~r/sziebert/~3/442351452/</link>
		<comments>http://sziebert.net/posts/go-vote-now/#comments</comments>
		<pubDate>Tue, 04 Nov 2008 18:14:26 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
		
		<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=34</guid>
		<description><![CDATA[<p>While I don&#8217;t usually post personal topics here, this one is deserving.  If you live in the US and you haven&#8217;t voted yet, go vote. Right now. You have *NO* excuses.  It is the *ONLY* way to insure that your opinion is heard.</p>
<p>a</p>
<p><a href="http://sziebert.net/posts/go-vote-now/">Go vote.  Now.</a></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/go-vote-now/feed/</wfw:commentRss>
		<feedburner:origLink>http://sziebert.net/posts/go-vote-now/</feedburner:origLink></item>
		<item>
		<title>Flickr style multiple file upload with jQuery</title>
		<link>http://feeds.feedburner.com/~r/sziebert/~3/391014842/</link>
		<comments>http://sziebert.net/posts/flickr-style-multiple-file-upload-with-jquery/#comments</comments>
		<pubDate>Fri, 12 Sep 2008 21:37:52 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
		
		<category><![CDATA[ActionScript]]></category>

		<category><![CDATA[Flash]]></category>

		<category><![CDATA[Software]]></category>

		<category><![CDATA[Tutorials]]></category>

		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=15</guid>
		<description><![CDATA[<p>A while back, <a href="http://gregoire.org/">Paul Gregoire</a> introduced me to the <a href="http://jquery.com">jQuery JavaScript library</a>.  It didn&#8217;t take long for me to realize the power and elegance of this library.  For the longest time, I&#8217;ve been wanting to take a shot at authoring a plugin for jQuery and I&#8217;ve finally gotten around to it.  So, it is my pleasure to announce the creation of the <a href="http://code.google.com/p/jquery-transmit">jquery.transmit plugin</a>.  It is a flash-backed multiple file upload utility with a user experience similar to that of Flickr&#8217;s current uploader.  The goals for the plugin were simple: Provide an easy-to-use interface, use flash to work around HTML and JavaScript based file upload issues, and wire it all together with jQuery. Getting started with the plugin is quite simple.  Import the necessary <acronym title="Cascading Style Sheets">CSS</acronym> and JavaScript dependencies, edit the supplied HTML to your liking and  invoke the plugin like so:</p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>    $(document).ready(function() {
        $('#transmit').transmit('http://mysite.com/upload/');
    });</pre>
</div>
<p></code></div>
</div>
<p>While the plugin is still very much in its infancy and should be considered a work in progress, it is my opinion that it is easier to shake out bugs using an iterative development process.  So, keeping that in mind, I&#8217;m hoping that a couple of you brave souls will wander over to <a href="http://code.google.com/p/jquery-transmit">googlecode</a> and give it a try.  Constructive feedback is very much appreciated.</p>
<p>a</p>
<p><a href="http://sziebert.net/posts/flickr-style-multiple-file-upload-with-jquery/">Flickr style multiple file upload with jQuery</a></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/flickr-style-multiple-file-upload-with-jquery/feed/</wfw:commentRss>
		<feedburner:origLink>http://sziebert.net/posts/flickr-style-multiple-file-upload-with-jquery/</feedburner:origLink></item>
		<item>
		<title>RESTful URLs with Spring MVC and UrlRewriteFilter</title>
		<link>http://feeds.feedburner.com/~r/sziebert/~3/378475154/</link>
		<comments>http://sziebert.net/posts/restful-urls-with-spring-mvc-and-urlrewritefilter/#comments</comments>
		<pubDate>Fri, 29 Aug 2008 23:05:00 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Spring Framework]]></category>

		<category><![CDATA[Tutorials]]></category>

		<category><![CDATA[Spring MVC]]></category>

		<category><![CDATA[UrlRewriteFilter]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=14</guid>
		<description><![CDATA[<p>While Spring 3.0 promises to support <acronym title="Representational State Transfer">REST</acronym> style URLs out of the box, it won&#8217;t ship until sometime later this year.  Spring 3.0 M1 will offer this functionality for anyone brave enough to work with potentially unstable technologies and should be available soon.  And while this is good news for those starting out on new projects (or those willing to undergo a significant refactoring), most won&#8217;t want to migrate their applications just for RESTful URLs.  All hope is not lost though, thanks to Paul Tuckey&#8217;s <a href="http://tuckey.org/urlrewrite/">UrlRewriteFilter</a>.<!--more--></p>
<p>With this short tutorial, I&#8217;ll demonstrate how easy it is to configure <tt>UrlRewriteFilter</tt> for use within your Spring MVC application.  I should mention that this technique will work well for just about any Java-based web framework, like JSF or Struts.  </p>
<p>For those of you that want to skip to the end, I&#8217;ve created a small, functional sample application which demonstrates the techniques described in this tutorial.  It can be downloaded <a href="http://sziebert.net/software/examples/RESTful.zip">here</a>.  </p>
<p>Getting started, we need to register the filter within our application&#8217;s web.xml file.</p>
<p><strong>web.xml</strong></p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>    &#60;!-- UrlRewriteFilter -->
    &#60;filter>
        &#60;filter-name>UrlRewriteFilter&#60;/filter-name>
        &#60;filter-class>
            org.tuckey.web.filters.urlrewrite.UrlRewriteFilter
        &#60;/filter-class>
        &#60;init-param>
            &#60;param-name>logLevel&#60;/param-name>
            &#60;param-value>WARN&#60;/param-value>
        &#60;/init-param>
    &#60;/filter>

    &#60;!-- UrlRewriteFilter Mapping -->
    &#60;filter-mapping>
        &#60;filter-name>UrlRewriteFilter&#60;/filter-name>
        &#60;url-pattern>/*&#60;/url-pattern>
    &#60;/filter-mapping></pre>
</div>
<p></code></div>
</div>
<p>That out of the way, we can dig into the application itself.  Let&#8217;s review an example controller class as it might exist in your application today.</p>
<p><strong>SprocketsController.java</strong></p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>@Controller
public class SprocketsController {

    private final SprocketService service;

    @Autowired
    public SprocketsController(SprocketService service) {
        this.service = service;
    }

    @RequestMapping("/sprockets/list.do")
    public String list(ModelMap model) {
        model.addAttribute("sprockets", service.list());
        return "sprocket/list";
    }

    @RequestMapping("/sprocket/display.do")
    public String display(@RequestParam("sprocketId") int sprocketId, ModelMap model) {
        model.addAttribute("sprocket", service.find(sprocketId));
        return "sprocket/display";
    }

    @RequestMapping("/sprocket/edit.do")
    public String edit(@RequestParam("sprocketId") int sprocketId, ModelMap model) {
        model.addAttribute("sprocket", service.find(sprocketId));
        return "sprocket/edit";
    }
}</pre>
</div>
<p></code></div>
</div>
<p>Our controller contains actions for displaying a list of sprockets, drilling down into each sprocket&#8217;s details and editing an individual sprocket.  Each action is mapped to a URI path via the <tt>@RequestMapping</tt> annotation and, as you can see, all three defined here handle requests mapped to the <tt>*.do</tt> extension.  The beauty of the solution I&#8217;m demonstrating here is that you should not need to make any changes to your application code at all.  That in mind, let&#8217;s move on to the interesting part, configuring our application to respond to a REST style URL like <tt>http://localhost:8080/sprocket/1234/edit</tt> instead of what we&#8217;ve got now: <tt>http://localhost:8080/sprocket/edit.do?sprocketId=1234</tt>.  You&#8217;ll need to create a new configuration file named <tt>urlrewrite.xml</tt> and make it available on the classpath. (For those with a distaste for XML based configuration, the latest version of the filter offers a means to generate the configuration via annotations.  Details on that can be found <a href="http://urlrewritefilter.googlecode.com/svn/trunk/src/doc/manual/3.1/annotation.html">here</a>.)  We&#8217;ll start our configuration by defining a few rules to handle the incoming requests.</p>
<p><strong>urlrewrite.xml</strong></p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>    &#60;rule>
        &#60;from>^/sprockets/$&#60;/from>
        &#60;to>/sprockets/list.do&#60;/to>
    &#60;/rule>
    &#60;rule>
        &#60;from>^/sprocket/([a-z0-9]+)/$&#60;/from>
        &#60;to>/sprocket/display.do?sprocketId=$1&#60;/to>
    &#60;/rule>
    &#60;rule>
        &#60;from>^/sprocket/([a-z0-9]+)/edit$&#60;/from>
        &#60;to>/sprocket/edit.do?sprocketId=$1&#60;/to>
    &#60;/rule></pre>
</div>
<p></code></div>
</div>
<p>Let&#8217;s take a look at what each one of these rules does.  The first rule states that the UrlRewriteFilter should transparently forward each request for <tt>http://localhost:8080/sprockets/</tt> to the existing application URL of <tt>http://localhost:8080/sprockets/list.do</tt>.  The second and third rules handle the display and edit requests.  These 2 rules define simple regular expressions that are parsed out and appended to the destination URI as query string parameters.  If you have more than 1 query string parameter, you&#8217;ll need to use <tt>&amp;</tt> XML entity.  (It should be noted that you can use wildcard matching <tt>(*)</tt> instead, however it lacks some of the flexibility offered by regular expressions.)  </p>
<p>That takes care of the inbound URLs, but we still have a problem.  Within our application, we have a number of links which point to the old URL structure.  No worries, <tt>UrlRewriteFilter</tt> tackles this issue with ease.  By examining the response, the filter can rewrite the existing links defined within <tt>anchor</tt> tags, i.e. <tt>&lt;a href=&#8221;&lt;c:url value=&#8217;/sprockets/list.do&#8217;/&gt;&#8221;&gt;Return to the list.&lt;/a&gt;</tt>.  Let&#8217;s take a look at the rule definitions to handle this.</p>
<p><strong>urlrewrite.xml</strong></p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>    &#60;outbound-rule>
        &#60;from>^/sprockets/list.do$&#60;/from>
        &#60;to>/sprockets/&#60;/to>
    &#60;/outbound-rule>
    &#60;outbound-rule>
        &#60;from>^/sprocket/display.do\?sprocketId=([a-z0-9]+)$&#60;/from>
        &#60;to>/sprocket/$1/&#60;/to>
    &#60;/outbound-rule>
    &#60;outbound-rule>
        &#60;from>^/sprocket/edit.do\?sprocketId=([a-z0-9]+)$&#60;/from>
        &#60;to>/sprocket/$1/edit&#60;/to>
    &#60;/outbound-rule></pre>
</div>
<p></code></div>
</div>
<p>More or less, these outbound rules are just the inverse of the inbound rule definitions.  All it takes is a simple regular expression to parse out the <tt>sprocketId</tt>.  One common gotcha to note here is that you need to add the <tt>\</tt> character before the start of the query string marked by the question mark.  If you don&#8217;t do this, the filter won&#8217;t be able to process your links.</p>
<p>Pretty easy, right?  With your rules in place, fire up your application and give it a try.  You can always examine the status of the filter by visiting <a href="http://127.0.0.1:8080/rewrite-status">http://127.0.0.1:8080/rewrite-status</a>.  If you&#8217;re a bit hesitant to try this out on your own app, fret not, I&#8217;ve created a simple, yet functional sample application which you can use to experiment with.  The example source code can be downloaded <a href="http://sziebert.net/software/examples/RESTful.zip">here</a>.</p>
<p>a</p>
<p><a href="http://sziebert.net/posts/restful-urls-with-spring-mvc-and-urlrewritefilter/">RESTful URLs with Spring MVC and UrlRewriteFilter</a></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/restful-urls-with-spring-mvc-and-urlrewritefilter/feed/</wfw:commentRss>
		<feedburner:origLink>http://sziebert.net/posts/restful-urls-with-spring-mvc-and-urlrewritefilter/</feedburner:origLink></item>
		<item>
		<title>Mac OSX + Subversion = Versions</title>
		<link>http://feeds.feedburner.com/~r/sziebert/~3/304736668/</link>
		<comments>http://sziebert.net/posts/mac-osx-subversion-versions/#comments</comments>
		<pubDate>Wed, 04 Jun 2008 18:58:46 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
		
		<category><![CDATA[Mac OS X]]></category>

		<category><![CDATA[Subversion]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=13</guid>
		<description><![CDATA[<p>This morning I received a shocking email&#8230; <a href="http://www.picodev.com/">Pico</a> and <a href="http://www.madebysofa.com/">Sofa</a> have finally released the beta of <a href="http://www.versionsapp.com/">Versions</a>, a brand-spanking-new Subversion client for the Mac.  Having been stuck with svnX for so long, Versions is a welcome addition to my development tool chest.  There are a few quirks when using the app.  For example, when right-clicking on the repository bookmark, I would have expected it to have entries for adding working copy bookmarks.  That is not the case, you&#8217;ll find that menu item only on the &#8220;+&#8221; button at the bottom of the interface.  Regardless, if you work on a Mac and use Subversion for source control, give <a href="http://www.versionsapp.com/">Versions</a> a look.</p>
<p>a</p>
<p><a href="http://sziebert.net/posts/mac-osx-subversion-versions/">Mac OSX + Subversion = Versions</a></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/mac-osx-subversion-versions/feed/</wfw:commentRss>
		<feedburner:origLink>http://sziebert.net/posts/mac-osx-subversion-versions/</feedburner:origLink></item>
		<item>
		<title>Jedai Framework for Red5</title>
		<link>http://feeds.feedburner.com/~r/sziebert/~3/282981680/</link>
		<comments>http://sziebert.net/posts/jedai-framework-for-red5/#comments</comments>
		<pubDate>Sat, 03 May 2008 23:00:43 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
		
		<category><![CDATA[ActionScript]]></category>

		<category><![CDATA[Flash Media Server]]></category>

		<category><![CDATA[Red5]]></category>

		<category><![CDATA[jedai]]></category>

		<guid isPermaLink="false">http://sziebert.net/?p=12</guid>
		<description><![CDATA[<p>As the Red5 media server continues to mature, new and exciting additions are announced with greater frequency.  Once such addition to Red5 is the Jedai project.  Anyone familiar with Flash Media Server knows that it provides a solid component library for rapid development of collaborative media applications.  With the introduction of the Jedai project, Red5 is no longer lacking in the area.<!--more-->  </p>
<p>The project consists of two main parts, the Jedia Networking Framework (JNF) and the Jedai Collaboration Suite (JCS).  The Networking Framework delivers a development stack that &#8220;builds upon the services that most real-time applications need&#8221; such as user, stream and data management.  The Collaboration Suite is a set of reusable components providing services such as authentication, text chat and video publishing and is designed to be used directly with the JNF.  Leveraging these two pieces gives Red5 application developers a great deal of power and flexibility with a minimum of effort.  </p>
<p>From the project developers themselves: &#8220;We have seen the need for this framework for quite some time, and here is our answer. Please, feel free to try it out and watch as it becomes a standard in real-time application development with Red5 and Flash.&#8221;  </p>
<p>Check it out here: <a href="http://code.google.com/p/jedai/">http://code.google.com/p/jedai/</a></p>
<p>a</p>
<p><a href="http://sziebert.net/posts/jedai-framework-for-red5/">Jedai Framework for Red5</a></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/jedai-framework-for-red5/feed/</wfw:commentRss>
		<feedburner:origLink>http://sziebert.net/posts/jedai-framework-for-red5/</feedburner:origLink></item>
		<item>
		<title>Open letter to the Chinese blogger stealing my work…</title>
		<link>http://feeds.feedburner.com/~r/sziebert/~3/230548161/</link>
		<comments>http://sziebert.net/posts/open-letter-to-the-chinese-blogger-stealing-my-work/#comments</comments>
		<pubDate>Wed, 06 Feb 2008 21:57:47 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
		
		<category><![CDATA[WTF]]></category>

		<guid isPermaLink="false">http://sziebert.net/posts/open-letter-to-the-chinese-blogger-stealing-my-work/</guid>
		<description><![CDATA[<p>Dear Sir/Madam:</p>
<p>Thank you for taking the time to read through my posts and link to them.  Unfortunately, you have managed to offend me.  Instead of linking to my post and providing a summary like most considerate bloggers would, you have chosen to copy the article in whole, download my sample code and republish it WITHOUT so much as a single line giving credit to me as the original author.  To me, this is unacceptable.  Please update your pingbacks to correctly specify me as the author or I&#8217;ll be forced to ban you from reading my blog.</p>
<p>Regards,<br />
Carl Sziebert</p>
<p>a</p>
<p><a href="http://sziebert.net/posts/open-letter-to-the-chinese-blogger-stealing-my-work/">Open letter to the Chinese blogger stealing my work&#8230;</a></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/open-letter-to-the-chinese-blogger-stealing-my-work/feed/</wfw:commentRss>
		<feedburner:origLink>http://sziebert.net/posts/open-letter-to-the-chinese-blogger-stealing-my-work/</feedburner:origLink></item>
		<item>
		<title>13949712720901ForOSX</title>
		<link>http://feeds.feedburner.com/~r/sziebert/~3/187961833/</link>
		<comments>http://sziebert.net/posts/13949712720901forosx/#comments</comments>
		<pubDate>Tue, 20 Nov 2007 22:46:06 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
		
		<category><![CDATA[Apple, Inc.]]></category>

		<category><![CDATA[Java]]></category>

		<category><![CDATA[Mac OS X]]></category>

		<guid isPermaLink="false">http://sziebert.net/posts/13949712720901forosx/</guid>
		<description><![CDATA[<p>You&#8217;ve read my rant about Java 6 being missing from the recent Leopard release, now you can help make a poor, not-so-humble geek&#8217;s wish come true. All you need to do is post a short entry on your blog with a reference to the string &#8216;<tt>13949712720901ForOSX</tt>&#8216;. Doing so, means that you are casting your vote to tell Apple to fix it&#8217;s cranio-rectal inversion.  Plus, you&#8217;ll be helping me and the 5 (there&#8217;s many, many more out there I am sure) other developers that actually write Java on a Mac out a ton.  But why &#8216;<tt>13949712720901ForOSX</tt>&#8216; you ask?  The actual meaning of the string is a bit entertaining.  Translated from decimal notation to hex, the numeric portion is &#8216;<tt>0xCAFEBABE405&#8242;</tt>.  Yup, you read that correctly.  Who says <del datetime="2008-10-10T21:34:11+00:00">Apple</del> Sun engineers don&#8217;t have a sense of humor?  What&#8217;s more entertaining is that 405 is the HTTP response code for &#8216;<tt>Method not found</tt>.&#8217;  You can read more about the effort to bring Java 6 to a Mac near you and the meaning behind the magical string at <a href="http://blogs.sun.com/bblfish/entry/vote_for_java6_on_leopard">the Sun Babelfish blog</a>.</p>
<p>a</p>
<p><a href="http://sziebert.net/posts/13949712720901forosx/">13949712720901ForOSX</a></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/13949712720901forosx/feed/</wfw:commentRss>
		<feedburner:origLink>http://sziebert.net/posts/13949712720901forosx/</feedburner:origLink></item>
		<item>
		<title>WTF:  Apple ships Leopard without Java 6</title>
		<link>http://feeds.feedburner.com/~r/sziebert/~3/177790355/</link>
		<comments>http://sziebert.net/posts/wtf-apple-ships-leopard-without-java-6/#comments</comments>
		<pubDate>Wed, 31 Oct 2007 16:59:17 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
		
		<category><![CDATA[Apple, Inc.]]></category>

		<category><![CDATA[Java]]></category>

		<category><![CDATA[Mac OS X]]></category>

		<category><![CDATA[WTF]]></category>

		<guid isPermaLink="false">http://sziebert.net/posts/wtf-apple-ships-leopard-without-java-6/</guid>
		<description><![CDATA[<p>Having been a Java developer for the better part of a decade and an Apple fanboy for longer than that, I am left wondering what the hell they were thinking when they decided to not add Java 6 to Leopard.  Keeping in mind, of course, that Apple has been notoriously bad about updating Java for OS X, the release of Leopard took just over 2 years to complete.  They couldn&#8217;t find the time to get it done?<!--more-->  James Gosling is quoted for saying that Mac OS X is his preferred platform, but that he laments Apple&#8217;s decision to &#8216;roll their own&#8217; JDK.  I, like many other developers, believe that the time has come for Sun to regain control and promote Java on the Mac to a first class citizen by providing a JDK along side Windows, Linux and Solaris.  It has been well over a year since Apple posted the preview release of JDK6. Then in preparation for the launch of Leopard, the download was removed from the ADC site leading many of us to believe that our wish had come true.  Sadly, this is not the case and is the number one reason why I <strong>won&#8217;t</strong> be upgrading anytime soon.  Java is my bread and butter, it is how I keep my bills paid.  So until Apple gets their shit together, I&#8217;m sticking with Tiger and the preview release of Java 6.</p>
<p>a</p>
<p><a href="http://sziebert.net/posts/wtf-apple-ships-leopard-without-java-6/">WTF:  Apple ships Leopard without Java 6</a></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/wtf-apple-ships-leopard-without-java-6/feed/</wfw:commentRss>
		<feedburner:origLink>http://sziebert.net/posts/wtf-apple-ships-leopard-without-java-6/</feedburner:origLink></item>
		<item>
		<title>Remote debugging Red5 applications</title>
		<link>http://feeds.feedburner.com/~r/sziebert/~3/157300425/</link>
		<comments>http://sziebert.net/posts/remote-debugging-red5-applications/#comments</comments>
		<pubDate>Sun, 16 Sep 2007 19:53:34 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
		
		<category><![CDATA[Eclipse]]></category>

		<category><![CDATA[Java]]></category>

		<category><![CDATA[Red5]]></category>

		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://sziebert.net/posts/remote-debugging-red5-applications/</guid>
		<description><![CDATA[<p>Red5<a class="sup" href="#red5">[1]</a> contributor <a href="http://osflash.org/paulgregoire">Paul Gregoire</a> recently added a new server startup script targeted specifically at application debugging.  The script is quite simple in nature and is provided in both Windows and Unix flavors.  Take note, however, that this script is exclusive to the standalone version of Red5.  Debugging the WAR version of the server is quite a different task.  To demonstrate the ease of debugging your applications, I&#8217;ll walk through a simple example using Eclipse<a class="sup" href="#eclipse">[2]</a> and the source code from my <a href="http://sziebert.net/posts/server-side-stream-recording-with-red5/">stream recording tutorial</a>.<!--more--> </p>
<p>First things first, you&#8217;ll want to make sure you have the latest code from Red5&#8217;s subversion repository.  If you do not run against trunk, fear not, you&#8217;ll just need to create the scripts manually.  Both versions are shown here:</p>
<p><strong>Windows</strong></p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>@echo off

set JAVA_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y

if not "%JAVA_HOME%" == "" goto launchRed5

:launchRed5
"%JAVA_HOME%/bin/java" -Djava.security.manager -Djava.security.policy=conf/red5.policy %JAVA_OPTS% -cp red5.jar;conf;bin;%CLASSPATH% org.red5.server.Standalone
goto finaly

:err
echo JAVA_HOME environment variable not set! Take a look at the readme.
pause

:finaly
pause</pre>
</div>
<p></code></div>
</div>
<p><strong>Unix</strong></p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>#!/bin/bash

JAVA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y"

for JAVA in "$JAVA_HOME/bin/java" "/usr/bin/java" "/usr/local/bin/java"
do
  if [ -x $JAVA ]
  then
    break
  fi
done

if [ ! -x $JAVA ]
then
  echo "Unable to locate java. Please set JAVA_HOME environment variable."
  exit
fi

# start red5
exec $JAVA -Djava.security.manager -Djava.security.policy=conf/red5.policy $JAVA_OPTS -cp red5.jar:conf:$CLASSPATH org.red5.server.Standalone</pre>
</div>
<p></code></div>
</div>
<p>Make sure you&#8217;ve got the file permissions set correctly on Unix platforms.  If not, updating the file permissions is as simple as <tt>chmod 755 red5_debug.sh</tt>.  Double check to insure that your application is installed in the Red5 webapps directory and configured properly.  If not, you&#8217;ll need to deploy it now.  Start the server from the console.  Don&#8217;t expect to see the normal server log statements just yet.  The only statement we are interested in at this point is &#8220;<tt>Listening for transport dt_socket at address: 8787</tt>&#8220;.  You should be seeing something like this:</p>
<p><a href="http://sziebert.net/images/console-waiting.gif" rel="lightbox-debugging" title="Console"><img src="http://sziebert.net/images/thumbs/console-waiting.jpg" alt="Console" /></a></p>
<p>Next, we&#8217;ll need to create a debugging profile in Eclipse.  Start it now if it is not already running and make sure that your project is open in the workspace.  Mine looks something like this:</p>
<p><a href="http://sziebert.net/images/eclipse.gif" rel="lightbox-debugging" title="Eclipse"><img src="http://sziebert.net/images/thumbs/eclipse.jpg" alt="Eclipse" /></a></p>
<p>Find the small bug icon in the Eclipse toolbar, click it and choose &#8220;<tt>Open Debug Dialog&#8230;</tt>&#8220;.  Select the &#8220;<tt>Remote Java Application</tt>&#8221; entry in the list, then right click and choose &#8220;<tt>New</tt>&#8220;.  By default, Eclipse will name this debugging profile after the class you currently have selected in the editor.  I&#8217;ve changed it to reflect the name of the project I&#8217;m working with at the moment.  The only other changes we need to make are to alter the default port number from 8000 to 8787 and check the &#8220;<tt>Allow termination of remote VM</tt>&#8221; box.  The second step here is not really necessary, but I like having the option to kill the remote server from Eclipse.  Here&#8217;s what you should have:</p>
<p><a href="http://sziebert.net/images/debug-dialog.gif" rel="lightbox-debugging" title="Debug Dialog"><img src="http://sziebert.net/images/thumbs/debug-dialog.jpg" alt="Debug Dialog" /></a></p>
<p>Click &#8220;<tt>Apply</tt>&#8220;, then &#8220;<tt>Debug</tt>&#8220;.  Eclipse has now attached a socket listener to the remote JVM and Red5 should be starting in the console window you opened earlier, complete with all of the standard logging output shown here:</p>
<p><a href="http://sziebert.net/images/console-started.gif" rel="lightbox-debugging" title="Console"><img src="http://sziebert.net/images/thumbs/console-started.jpg" alt="Console" /></a></p>
<p>If you&#8217;ve never opened the debugging perspective in Eclipse before, it should prompt you to do so.  If not, select &#8220;<tt>Window &#8211;> Open Perspective &#8211;> Debug</tt>&#8220;.  Select the line at which you would like to set a breakpoint and double click in the gutter.  The debug perspective should have appeared and you should see your breakpoint:</p>
<p><a href="http://sziebert.net/images/eclipse-debug.gif" rel="lightbox-debugging" title="Eclipse Debug Perspecive"><img src="http://sziebert.net/images/thumbs/eclipse-debug.jpg" alt="Eclipse Debug Perspecive" /></a></p>
<p>At this point you&#8217;ll need to start the execution path of your application.  Fire up your flash or flex app and connect to Red5.  For this example, I&#8217;ve opened a browser and pointed it at the broadcast SWF of my stream recording tutorial.  Given that you are using the same project I am, you should see this (Sans my ugly mug, of course.):    </p>
<p><a href="http://sziebert.net/images/broadcast.jpg" rel="lightbox-debugging" title="Broadcast Flash App"><img src="http://sziebert.net/images/thumbs/broadcast.jpg" alt="Broadcast Flash App" /></a></p>
<p>Upon triggering your breakpoint, your application will cease to respond and Eclipse should come into focus.  The debugger will highlight the line of code next in the execution tree.  You&#8217;ll see something like the following:</p>
<p><a href="http://sziebert.net/images/eclipse-breakpoint.gif" rel="lightbox-debugging" title="Eclipse Debugger"><img src="http://sziebert.net/images/thumbs/eclipse-breakpoint.jpg" alt="Eclipse Debugger" /></a></p>
<p>That&#8217;s it!  You are now debugging your Red5 application.  If you aren&#8217;t sure what to do next, I would suggest that you read this <a href="http://www.ibm.com/developerworks/opensource/library/os-ecbug/">article</a> over at IBM&#8217;s developerWorks. </p>
<p>With these startup scripts, it is even possible to debug Red5 itself.  You&#8217;ll need to have the latest code checked out from Subversion and the project open in Eclipse.  Start the server in the same manner, create or open the debug profile and start debugging.</p>
<p>1. <a name="red5" href="http://osflash.org/red5">http://osflash.org/red5</a> For those that aren’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="eclipse" href="http://www.eclipse.org">www.eclipse.org</a> Eclipse is an open source community whose projects are focused on building an open development platform comprised of extensible frameworks, tools and runtimes for building, deploying and managing software across the lifecycle.</p>
<p>a</p>
<p><a href="http://sziebert.net/posts/remote-debugging-red5-applications/">Remote debugging Red5 applications</a></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/remote-debugging-red5-applications/feed/</wfw:commentRss>
		<feedburner:origLink>http://sziebert.net/posts/remote-debugging-red5-applications/</feedburner:origLink></item>
		<item>
		<title>Server-side stream recording with Red5</title>
		<link>http://feeds.feedburner.com/~r/sziebert/~3/152317130/</link>
		<comments>http://sziebert.net/posts/server-side-stream-recording-with-red5/#comments</comments>
		<pubDate>Wed, 05 Sep 2007 02:48:25 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
		
		<category><![CDATA[ActionScript]]></category>

		<category><![CDATA[Flash Media Server]]></category>

		<category><![CDATA[Java]]></category>

		<category><![CDATA[Red5]]></category>

		<category><![CDATA[Software]]></category>

		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://sziebert.net/posts/server-side-stream-recording-with-red5/</guid>
		<description><![CDATA[<p>While most developers are content to record video using the <tt>NetStream.publish(&#8221;streamName&#8221;, &#8220;record&#8221;)</tt> API, it is sometimes useful to take FLV snippets from the publishing stream instead.  In my opinion, this is one of the greatest features of Flash Media Server (FMS) and Red5.  Utilizing this strategy allows the application developer to precisely control when and how much of the video is recorded.  While recording via the <tt>NetStream</tt> function has been available in Red5 since the beginning, recording video from the server-side application has not.  In this post, I&#8217;ll demonstrate Red5&#8217;s ability to record an FLV with a very simple pair of publish and subscribe flash applications.<!--more--> </p>
<p>I&#8217;ll jump right in by creating a simple ApplicationAdapter subclass.  This step isn&#8217;t really necessary, however I feel that it is good practice when creating Red5 applications.  As your application grows in functionality, you&#8217;ll have the most essential building block ready to go. </p>
<p><strong>Application.java</strong></p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>public class Application extends ApplicationAdapter {

	...

	/**
	 * Delegate method used to accept/reject incoming connection requests.
	 *
	 * @param conn
	 * @param params
	 * @return true/false
	 */
	@Override
	public boolean roomConnect(IConnection conn, Object[] params) {
		log.debug("New connection attempt from " + conn.getRemoteAddress() + "...");
		// Insure that the listeners are properly attached.
		return super.roomConnect(conn, params);
	}

	/**
	 * Delegate method which logs connection/client/user disconnections.
	 *
	 * @param conn
	 */
	@Override
	public void roomDisconnect(IConnection conn) {
		log.debug("Connection closed by " + conn.getRemoteAddress() + "...");
		// Call the super class to insure that all listeners are properly
		// dismissed.
		super.roomDisconnect(conn);
	}
}</pre>
</div>
<p></code></div>
</div>
<p>As you can see, there isn&#8217;t much to it, just a couple of logging statements to track new connections to the application.  Next, I&#8217;ll define a simple service bean to handle the <tt>NetConnection</tt> calls to start and stop the stream recordings.</p>
<p><strong>StreamManager.java</strong></p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>public class StreamManager {

	...

	/**
	 * Start recording the publishing stream for the specified
	 * IConnection.
	 *
	 * @param conn
	 */
	public void recordShow(IConnection conn) {
		log.debug("Recording show for: " + conn.getScope().getContextPath());
		String streamName = String.valueOf(System.currentTimeMillis());
		// Get a reference to the current broadcast stream.
		ClientBroadcastStream stream = (ClientBroadcastStream) app.getBroadcastStream(
				conn.getScope(), "hostStream");
		try {
			// Save the stream to disk.
			stream.saveAs(streamName, false);
		} catch (Exception e) {
			log.error("Error while saving stream: " + streamName, e);
		}
	}

	/**
	 * Stops recording the publishing stream for the specified
	 * IConnection.
	 *
	 * @param conn
	 */
	public void stopRecordingShow(IConnection conn) {
		log.debug("Stop recording show for: " + conn.getScope().getContextPath());
		// Get a reference to the current broadcast stream.
		ClientBroadcastStream stream = (ClientBroadcastStream) app.getBroadcastStream(
				conn.getScope(), "hostStream");
		// Stop recording.
		stream.stopRecording();
	}

	...
}</pre>
</div>
<p></code></div>
</div>
<p>This is where the meat of the application lies.  The broadcast client starts recording the stream by calling <tt>streamManager.recordShow()</tt> and stops it by calling <tt>streamManager.stopRecordingShow()</tt>.  In the example broadcast application, I&#8217;ve added a button to the Stage and created a simple <tt>onClick</tt> function to invoke the server-side methods.</p>
<p><strong>BroadcastController.as</strong></p>
<div class='code_parent'>
<div class='code_title'>Code:</div>
<div class='code_child'><code>
<div class='pre_container'>
<pre>        /**
	 * Handle the record button click events.
	 */
	private function onClick(ev:Object):Void {
		// Record the stream by triggering a server event.
		if (ev.target.label == "Record") {
			// Tell the remote server to start recording.
			conn.call("streamManager.recordShow", null);
			// Re-label the button.
			button.label = "Stop";
		// Stop recording the stream.
		} else if (ev.target.label == "Stop") {
			// Tell the remote server to stop recording.
			conn.call("streamManager.stopRecordingShow", null);
			// Re-label the button.
			button.label = "Record";
		}
	}</pre>
</div>
<p></code></div>
</div>
<p>Take note, the name of the recorded stream differs from that of the publishing stream.  I am using a simple timestamp as a unique name for each new FLV.  It is even possible to reuse an existing FLV and append new video data to it.  Simply change the second argument of the <tt>stream.saveAs()</tt> method call to <tt>true</tt> while reusing the same stream name. Check the streams directory of the recorder application for the output files.  Reviewing the FLVs is as easy as opening them up with an FLV player<a class="sup" href="#wimpy">[1]</a>.   </p>
<p>While this is an interesting bit of functionality, the possibilities are much greater.  Consider, for example, a security application that needs to record video when the camera detects movement and also needs to have a unique file for each incident. With some minor tweaks to this example, you&#8217;ve got exactly that.  In addition, it would be quite easy to extend this application to extract a JPEG preview snapshot from each FLV using FFMPEG<a class="sup" href="#ffmpeg">[2]</a>.</p>
<p>The example source code for this post can be downloaded <a href="http://sziebert.net/downloads/Recorder.zip">here</a>.</p>
<p>1. <a name="wimpy" href="http://www.wimpyplayer.com/products/wimpy_standalone_flv_player.html">http://www.wimpyplayer.com</a> Wimpy Desktop FLV Player is a free cross platform (Mac and PC) standalone Flash Video FLV player for you, which will allow you to watch your FLV and SWF videos from your desktop.  Check it out.</p>
<p>2. <a name="ffmpeg" href="http://ffmpeg.mplayerhq.hu/index.html">http://ffmpeg.mplayerhq.hu/index.html</a> FFmpeg is a complete solution to record, convert and stream audio and video. It includes libavcodec, the leading audio/video codec library. FFmpeg is developed under Linux, but it can compiled under most operating systems, including Windows.</p>
<p>a</p>
<p><a href="http://sziebert.net/posts/server-side-stream-recording-with-red5/">Server-side stream recording with Red5</a></p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/server-side-stream-recording-with-red5/feed/</wfw:commentRss>
		<feedburner:origLink>http://sziebert.net/posts/server-side-stream-recording-with-red5/</feedburner:origLink></item>
	</channel>
</rss>
