<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>Carl Sziebert &#187; Tutorials</title>
	<atom:link href="http://sziebert.net/posts/category/tutorials/feed/" rel="self" type="application/rss+xml" />
	<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>
		<item>
		<title>Using Bcrypt with Spring Security</title>
		<link>http://sziebert.net/posts/using-bcrypt-with-spring-security/</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>
		</item>
		<item>
		<title>Server-side stream recording example updated</title>
		<link>http://sziebert.net/posts/server-side-stream-recording-updated/</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>
		</item>
		<item>
		<title>Red5 + Hibernate Revisited</title>
		<link>http://sziebert.net/posts/red5-hibernate-revisited/</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>
		</item>
		<item>
		<title>Flickr style multiple file upload with jQuery</title>
		<link>http://sziebert.net/posts/flickr-style-multiple-file-upload-with-jquery/</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>
<pre class="brush: jscript;">
    $(document).ready(function() {
        $('#transmit').transmit('http://mysite.com/upload/');
    });
</pre>
<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>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/flickr-style-multiple-file-upload-with-jquery/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>RESTful URLs with Spring MVC and UrlRewriteFilter</title>
		<link>http://sziebert.net/posts/restful-urls-with-spring-mvc-and-urlrewritefilter/</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://garagetech.googlecode.com/files/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>
<pre class="brush: xml;">
    &lt;!-- UrlRewriteFilter --&gt;
    &lt;filter&gt;
        &lt;filter-name&gt;UrlRewriteFilter&lt;/filter-name&gt;
        &lt;filter-class&gt;
            org.tuckey.web.filters.urlrewrite.UrlRewriteFilter
        &lt;/filter-class&gt;
        &lt;init-param&gt;
            &lt;param-name&gt;logLevel&lt;/param-name&gt;
            &lt;param-value&gt;WARN&lt;/param-value&gt;
        &lt;/init-param&gt;
    &lt;/filter&gt;

    &lt;!-- UrlRewriteFilter Mapping --&gt;
    &lt;filter-mapping&gt;
        &lt;filter-name&gt;UrlRewriteFilter&lt;/filter-name&gt;
        &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
    &lt;/filter-mapping&gt;
</pre>
<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>
<pre class="brush: java;">
@Controller
public class SprocketsController {

    private final SprocketService service;

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

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

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

    @RequestMapping(&quot;/sprocket/edit.do&quot;)
    public String edit(@RequestParam(&quot;sprocketId&quot;) int sprocketId, ModelMap model) {
        model.addAttribute(&quot;sprocket&quot;, service.find(sprocketId));
        return &quot;sprocket/edit&quot;;
    }
}
</pre>
<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>
<pre class="brush: xml;">
    &lt;rule&gt;
        &lt;from&gt;^/sprockets/$&lt;/from&gt;
        &lt;to&gt;/sprockets/list.do&lt;/to&gt;
    &lt;/rule&gt;
    &lt;rule&gt;
        &lt;from&gt;^/sprocket/([a-z0-9]+)/$&lt;/from&gt;
        &lt;to&gt;/sprocket/display.do?sprocketId=$1&lt;/to&gt;
    &lt;/rule&gt;
    &lt;rule&gt;
        &lt;from&gt;^/sprocket/([a-z0-9]+)/edit$&lt;/from&gt;
        &lt;to&gt;/sprocket/edit.do?sprocketId=$1&lt;/to&gt;
    &lt;/rule&gt;
</pre>
<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="&lt;c:url value='/sprockets/list.do'/&gt;"&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>
<pre class="brush: xml;">
    &lt;outbound-rule&gt;
        &lt;from&gt;^/sprockets/list.do$&lt;/from&gt;
        &lt;to&gt;/sprockets/&lt;/to&gt;
    &lt;/outbound-rule&gt;
    &lt;outbound-rule&gt;
        &lt;from&gt;^/sprocket/display.do\?sprocketId=([a-z0-9]+)$&lt;/from&gt;
        &lt;to&gt;/sprocket/$1/&lt;/to&gt;
    &lt;/outbound-rule&gt;
    &lt;outbound-rule&gt;
        &lt;from&gt;^/sprocket/edit.do\?sprocketId=([a-z0-9]+)$&lt;/from&gt;
        &lt;to&gt;/sprocket/$1/edit&lt;/to&gt;
    &lt;/outbound-rule&gt;
</pre>
<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.  </p>
<p><strong>The example source code can be downloaded <a href="http://garagetech.googlecode.com/files/RESTful.zip">here</a></strong>.</p>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/restful-urls-with-spring-mvc-and-urlrewritefilter/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Remote debugging Red5 applications</title>
		<link>http://sziebert.net/posts/remote-debugging-red5-applications/</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&#8242;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>
<pre class="brush: bash;">
@echo off

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

if not &quot;%JAVA_HOME%&quot; == &quot;&quot; goto launchRed5

:launchRed5
&quot;%JAVA_HOME%/bin/java&quot; -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>
<p><strong>Unix</strong></p>
<pre class="brush: bash;">
#!/bin/bash

JAVA_OPTS=&quot;-Xdebug -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y&quot;

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

if [ ! -x $JAVA ]
then
  echo &quot;Unable to locate java. Please set JAVA_HOME environment variable.&quot;
  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>
<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...</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 --> Open Perspective --> 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>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/remote-debugging-red5-applications/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Server-side stream recording with Red5</title>
		<link>http://sziebert.net/posts/server-side-stream-recording-with-red5/</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><strong>This tutorial has been updated. Please check out the <a href="http://sziebert.net/posts/server-side-stream-recording-updated/">new post</a>.</strong</p>
<p>While most developers are content to record video using the <tt>NetStream.publish(&#8220;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'll demonstrate Red5's ability to record an FLV with a very simple pair of publish and subscribe flash applications.<!--more--> </p>
<p>I'll jump right in by creating a simple ApplicationAdapter subclass.  This step isn't really necessary, however I feel that it is good practice when creating Red5 applications.  As your application grows in functionality, you'll have the most essential building block ready to go. </p>
<p><strong>Application.java</strong></p>
<pre class="brush: java;">
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(&quot;New connection attempt from &quot; + conn.getRemoteAddress() + &quot;...&quot;);
		// 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(&quot;Connection closed by &quot; + conn.getRemoteAddress() + &quot;...&quot;);
		// Call the super class to insure that all listeners are properly
		// dismissed.
		super.roomDisconnect(conn);
	}
}
</pre>
<p>As you can see, there isn't much to it, just a couple of logging statements to track new connections to the application.  Next, I'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>
<pre class="brush: java;">
public class StreamManager {

	...

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

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

	...
}
</pre>
<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'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>
<pre class="brush: as3;">
        /**
	 * Handle the record button click events.
	 */
	private function onClick(ev:Object):Void {
		// Record the stream by triggering a server event.
		if (ev.target.label == &quot;Record&quot;) {
			// Tell the remote server to start recording.
			conn.call(&quot;streamManager.recordShow&quot;, null);
			// Re-label the button.
			button.label = &quot;Stop&quot;;
		// Stop recording the stream.
		} else if (ev.target.label == &quot;Stop&quot;) {
			// Tell the remote server to stop recording.
			conn.call(&quot;streamManager.stopRecordingShow&quot;, null);
			// Re-label the button.
			button.label = &quot;Record&quot;;
		}
	}
</pre>
<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'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://garagetech.googlecode.com/files/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://www.ffmpeg.org/">http://www.ffmpeg.org/</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>
]]></description>
		<wfw:commentRss>http://sziebert.net/posts/server-side-stream-recording-with-red5/feed/</wfw:commentRss>
		<slash:comments>66</slash:comments>
		</item>
		<item>
		<title>Red5 + Hibernate</title>
		<link>http://sziebert.net/posts/red5-hibernate/</link>
		<comments>http://sziebert.net/posts/red5-hibernate/#comments</comments>
		<pubDate>Thu, 23 Aug 2007 17:07:37 +0000</pubDate>
		<dc:creator>Carl Sziebert</dc:creator>
				<category><![CDATA[ActionScript]]></category>
		<category><![CDATA[Hibernate]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Red5]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://sziebert.net/posts/red5-hibernate/</guid>
		<description><![CDATA[<p><strong>This tutorial has been updated. Please check out the <a href="http://sziebert.net/posts/red5-hibernate-revisited">new post</a>.</strong></p>
<p>Having followed the growth of the Red5 Media Server<a class="sup" href="#red5">[1]</a> from it&#8217;s fledgling 0.3 days, I&#8217;ve become fairly familiar with its offerings. One of the most frequently asked questions on the Red5 mailing list pertains to database connectivity for user authentication and application security.  I&#8217;ll attempt to tackle one solution here using Hibernate<a class="sup" href="#hibernate">[2]</a>, an object/relational persistence framework.<!--more-->  Because Red5 is implemented in Java and makes heavy use of the Spring Framework<a class="sup" href="#spring">[3]</a>, I&#8217;ll be sticking with it for the purposes of this post.  Hibernate should be familiar to most Java developers these days, or at least the concept of an ORM framework should be.  If not, then you&#8217;ve got some homework to do before continuing on here.  One other item of note, I won&#8217;t be covering MySQL<a class="sup" href="#mysql">[4]</a> in any detail here, even though it is required for the example code to run.  My goal is to cover the integration of the technologies and not to reiterate the numerous introductions already available.</p>
<p>I&#8217;ll start by defining a simple Hibernate-backed User object and it&#8217;s mapping file.  Note: I&#8217;ve also included an annotated version of the User object in case you would prefer to run without mapping files.  </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;

        ...
}
</pre>
<p><strong>User.hbm.xml:</strong></p>
<pre class="brush: xml;">
&lt;hibernate-mapping package=&quot;net.sziebert.red5.adapter.entity&quot;&gt;
	&lt;class name=&quot;User&quot; table=&quot;users&quot;&gt;
		&lt;id name=&quot;id&quot; type=&quot;long&quot; column=&quot;id&quot;&gt;
			&lt;generator class=&quot;native&quot;/&gt;
		&lt;/id&gt;
		&lt;natural-id&gt;
			&lt;property name=&quot;userName&quot; column=&quot;user_name&quot; length=&quot;32&quot; not-null=&quot;true&quot; unique=&quot;true&quot; /&gt;
		&lt;/natural-id&gt;
		&lt;property name=&quot;password&quot; not-null=&quot;true&quot; /&gt;

		...

	&lt;/class&gt;
&lt;/hibernate-mapping&gt;
</pre>
<p>Both are very straight forward.  The User class defines fields for a unique identifier and the user&#8217;s credentials. It is mapped to the users table via Users.hbm.xml.  At this point, a Hibernate session factory and datasource definition are necessary.  I&#8217;ve defined both in the red5-web.xml file. This file is the means by which Red5 applications wire together resources and define dependencies.</p>
<p><strong>red5-web.xml:</strong></p>
<pre class="brush: xml;">
&lt;bean id=&quot;dataSource&quot; class=&quot;org.apache.commons.dbcp.BasicDataSource&quot; destroy-method=&quot;close&quot;&gt;
        &lt;property name=&quot;driverClassName&quot; value=&quot;${jdbc.driverClassName}&quot; /&gt;
        &lt;property name=&quot;url&quot; value=&quot;${jdbc.url}&quot; /&gt;
        &lt;property name=&quot;username&quot; value=&quot;${jdbc.username}&quot; /&gt;
        &lt;property name=&quot;password&quot; value=&quot;${jdbc.password}&quot; /&gt;
    &lt;/bean&gt;

    &lt;bean id=&quot;sessionFactory&quot; class=&quot;org.springframework.orm.hibernate3.LocalSessionFactoryBean&quot;&gt;
        &lt;property name=&quot;dataSource&quot; ref=&quot;dataSource&quot; /&gt;
        &lt;property name=&quot;mappingResources&quot;&gt;
            &lt;list&gt;
                &lt;value&gt;net/sziebert/red5/adapter/entity/User.hbm.xml&lt;/value&gt;
            &lt;/list&gt;
        &lt;/property&gt;
        &lt;property name=&quot;hibernateProperties&quot;&gt;
            &lt;props&gt;
                &lt;prop key=&quot;hibernate.dialect&quot;&gt;org.hibernate.dialect.MySQLInnoDBDialect&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.show_sql&quot;&gt;true&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.format_sql&quot;&gt;true&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.cache.use_query_cache&quot;&gt;true&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.bytecode.use_reflection_optimizer&quot;&gt;true&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.current_session_context_class&quot;&gt;thread&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.cache.provider_class&quot;&gt;org.hibernate.cache.HashtableCacheProvider&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.hbm2ddl.auto&quot;&gt;update&lt;/prop&gt;
            &lt;/props&gt;
        &lt;/property&gt;
    &lt;/bean&gt;
</pre>
<p>If you choose to take advantage of Hibernate Annotations, you&#8217;ll need to modify your session factory definition to use the AnnotationSessionFactoryBean template.</p>
<p><strong>red5-web.xml:</strong></p>
<pre class="brush: xml;">
&lt;bean id=&quot;sessionFactory&quot; class=&quot;org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean&quot;&gt;
        &lt;property name=&quot;dataSource&quot; ref=&quot;dataSource&quot; /&gt;
        &lt;property name=&quot;annotatedClasses&quot;&gt;
            &lt;list&gt;
            	&lt;value&gt;net.sziebert.red5.adapter.entity.User&lt;/value&gt;
            &lt;/list&gt;
        &lt;/property&gt;
        &lt;property name=&quot;annotatedPackages&quot;&gt;
            &lt;list&gt;
                &lt;value&gt;net.sziebert.red5.adapter.entity&lt;/value&gt;
            &lt;/list&gt;
        &lt;/property&gt;
        &lt;property name=&quot;hibernateProperties&quot;&gt;
            &lt;props&gt;
                &lt;prop key=&quot;hibernate.dialect&quot;&gt;org.hibernate.dialect.MySQLInnoDBDialect&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.show_sql&quot;&gt;true&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.format_sql&quot;&gt;true&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.query.factory_class&quot;&gt;org.hibernate.hql.classic.ClassicQueryTranslatorFactory&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.cache.use_query_cache&quot;&gt;true&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.bytecode.use_reflection_optimizer&quot;&gt;true&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.current_session_context_class&quot;&gt;thread&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.cache.provider_class&quot;&gt;org.hibernate.cache.HashtableCacheProvider&lt;/prop&gt;
                &lt;prop key=&quot;hibernate.hbm2ddl.auto&quot;&gt;update&lt;/prop&gt;
            &lt;/props&gt;
        &lt;/property&gt;
    &lt;/bean&gt;
</pre>
<p>Sticking with patterns most often referenced by other developers/authors, I&#8217;ll define a simple data access object and service layer next. Spring offers a template for Hibernate usage which plays very nicely with its transaction management facilities which I&#8217;ll cover later.</p>
<p><strong>HibernateApplicationDAO.java:</strong></p>
<pre class="brush: java;">
public class HibernateApplicationDAO extends HibernateDaoSupport implements ApplicationDAO {
	...

	/**
	 * @see ApplicationDAO#getUser(String, String)
	 */
	public User getUser(String user, String pass) {
		log.debug(&quot;Retrieving user from the database.&quot;);
		// Ask Hibernate to query for the user based upon the specified user/pass.
		Criteria crit = getSession().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) {
			log.warn(&quot;User does not exist for credentials: &quot; + user + &quot;/&quot; + pass);
			throw new ObjectRetrievalFailureException(User.class, user);
		}
		// Return the results.
		return u;
	}
}
</pre>
<p><strong>ApplicationServiceImpl.java:</strong></p>
<pre class="brush: java;">
public class ApplicationServiceImpl implements ApplicationService {

	...

	/**
	 * @see ApplicationService#getUser(String, String)
	 */
	public User getUser(String user, String pass) throws ServiceException {
		log.debug(&quot;Looking up user for user/pass of: &quot; + user + &quot;/&quot; + pass);
		try {
			// Return the result of the data access call.
			return dao.getUser(user, pass);
		} catch (Exception e) {
			log.error(&quot;Could not load user!&quot;, e);
			throw new ServiceException(&quot;Could not load user!&quot;, e);
		}
	}
}
</pre>
<p>You&#8217;ll want to take note of the red5-web.xml definition for the ApplicationService implementation.  It extends the TransactionProxyFactoryBean definition.  By defining the HibernateTransactionManager and this proxy template, we automagically get a Spring-managed Hibernate transaction every time we access the service layer to look up the User.  This means that you can skip the boilerplate code for opening a session and starting a transaction.  </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>I&#8217;ll wrap up the Red5 application definitions with the injection of the ApplicationService object into the ApplicationAdapter subclass, defined in red5-web.xml as web.handler.   The user authentication process happens within the ApplicationAdapter subclass, Application.java.  When a user with valid credentials connects to Red5, the application accepts the connection attempt and allows the user to stay connected.  In all other cases, the connection attempt is rejected and the connection is closed.</p>
<p><strong>red5-web.xml:</strong></p>
<pre class="brush: xml;">
&lt;bean id=&quot;web.handler&quot; class=&quot;net.sziebert.red5.adapter.Application&quot; singleton=&quot;true&quot;&gt;
    &lt;property name=&quot;applicationService&quot; ref=&quot;applicationService&quot; /&gt;
&lt;/bean&gt;
</pre>
<p><strong>Application.java:</strong></p>
<pre class="brush: java;">
public class Application extends ApplicationAdapter {

	...

	public boolean roomConnect(IConnection conn, Object[] params) {
		log.debug(&quot;New connection attempt from &quot; + conn.getRemoteAddress() + &quot;...&quot;);
		// 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 (StringUtils.isNotBlank(userName) &amp;&amp;
				StringUtils.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;
	}	

	...
}
</pre>
<p>The ActionScript side of things is also very straight forward.  I&#8217;ve created a simple client SWF which passes the specified user credentials as part of the NetConnection.connect() call and defines callback functions for handling the results of the connection attempt.  The results are also logged to a TextArea instance for convenient review.</p>
<p><strong>HibernateController.as:</strong></p>
<pre class="brush: as3;">
class net.sziebert.ria.HibernateController {

	...

	/**
	 * Initialize the connection to the Red5 media server.
	 */
	private function initConnection(user:String, pass:String):Void {
		trace(className + &quot;: initConnection(&quot; + user + &quot;, &quot; + pass + &quot;)&quot;);
		// Create the new connection object.
		conn = new Red5Connection({server:&quot;localhost&quot;, app:&quot;hibernate&quot;, room:&quot;test&quot;});
		// Add the NetConnection event listeners
		conn.addEventListener(&quot;onConnect&quot;, Delegate.create(this, onConnect));
		conn.addEventListener(&quot;onReject&quot;, Delegate.create(this, onReject));
		conn.addEventListener(&quot;onClose&quot;, Delegate.create(this, onClose));
		conn.addEventListener(&quot;onFail&quot;, Delegate.create(this, onFail));
		// Connect to the remote server
		log(&quot;Connecting to &quot; + conn.getServerUrl());
		conn.connect(conn.getServerUrl(), user, pass);
	}

	...
}
</pre>
<p>That&#8217;s more or less it.  Take a look over the <a href="http://sziebert.net/software/examples/Red5+Hibernate.zip">example code</a>, drop it into your Red5 install and let&#8217;er rip.  Keep in mind that you&#8217;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&#8217;ll also need to add your user data to the tables once Hibernate has generated the schema.</p>
<p><strong>This tutorial has been updated. Please check out the <a href="http://sziebert.net/posts/red5-hibernate-revisited">new post</a> for the latest source code bundle.</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/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>
