Jruby scripting explained
Overview
I am pretty new to red5 and had some trouble getting any of my jruby apps to work with it. The only other example that I could find was the scripting how-to guide and I personally think it is geared more towards seasoned red5 developers. So this will be my attempt at making jruby scripting and scripting in general with red5 a little easier for newbs such as my self. This tutorial assumes that you have the latest version of red5 from trunk installed and working correctly. I also use apache's ant to build the more complicated example.
Basic Application
The first example is going to assume that you have no java services defined and only have the main application(main.rb). This will cover the required directory structure and required files(took me a long time to figure this out). This may seem very simple to more seasoned red5 developers but it is major hang-up for new users to the scripting features in red5. Also, I am using java version 1.6.0_02 but this first example should work with any version that supports scripting. However, I have read that there are issues with older versions and red5 scripting.
Webapp Directory Structure
As you may already be aware, all applications should be located in the red5/webapps directory. This seems really simple now that I am aware of what is required but at first I had no clue what my basic directory structure should be. Also, please note that we will use a slightly different process for applications with java services and I will explain that in more detail later on in the tutorial. In this tutorial red5 will represent the red5 root directory. I will also use the webapp name of red5Jruby throughout this tutorial.
The basic configuration files can be found in red5/doc/templates/myapp . To make things easier you can copy the contents of that directory to red5/webapps/yourApp
red5/ #red5 root directory ...webapps/ #red5 web applications directory .....red5Jruby/ #our application .........WEB-INF/ #contains all of our application's files i.e. configs and application sources ..............classes/ #contains our complied java classes and scripting sources ..................applications/ #contains our scripting sources ........................main.rb #our jruby implementation of the red5 application adapter ..............lib/ #our application's lib directory ................slf4j-api-1.4.3.jar #core api. This jar should be located in red5/lib. You will need to copy it into this directory ..............web.xml #our application settings. This file is located in red5/doc/templates/myapp/WEB-INF ..............red5-web.xml #our application's web handler and services definitions ..............red5-web.properties #our application's vitualHosts and context path
The configuration files should be pretty easy to understand. The only one that I am going to cover in this tutorial is the red5-web.xml. Which contains our web handler and services definitions. Below is an excerpt from the red5-web.xml that defines our application web handler. Please see the scripting how-to guide for more information.
#red5/webapps/red5Jruby/WEB-INF/red5-web.xml
<!-- Our application web handler -->
<bean id="web.handler" class="org.springframework.scripting.jruby.JRubyScriptFactory">
<constructor-arg index="0" value="classpath:applications/main.rb"/>
<constructor-arg index="1">
<list>
<value>org.red5.server.api.IScopeHandler</value>
<value>org.red5.server.adapter.IApplication</value>
</list>
</constructor-arg>
</bean>
Ruby application adapter
I am going to use the main.rb from the olfaDemo as it is a good basic example. In later tutorials I will explain the application adapter in more detail. The focus of this tutorial is to get a basic application setup and working.
# JRuby - style
require 'java'
module RedFive
include_package "org.red5.server.api"
include_package "org.red5.server.api.stream"
include_package "org.red5.server.api.stream.support"
include_package "org.red5.server.adapter"
include_package "org.red5.server.stream"
end
#
# application.rb - a translation into Ruby of the ofla demo application, a red5 example.
#
# @author Paul Gregoire
#
class Application < RedFive::ApplicationAdapter
attr_reader :appScope, :serverStream
attr_writer :appScope, :serverStream
def initialize
#call super to init the superclass, in this case a Java class
super
puts "Initializing ruby application"
end
def appStart(app)
puts "Jruby application started"
@appScope = app
return true
end
def appConnect(conn, params)
puts "Ruby appConnect"
measureBandwidth(conn)
puts "Ruby appConnect 2"
if conn.instance_of?(RedFive::IStreamCapableConnection)
puts "Got stream capable connection"
sbc = RedFive::SimpleBandwidthConfigure.new
sbc.setMaxBurst(8388608)
sbc.setBurst(8388608)
sbc.setOverallBandwidth(8388608)
conn.setBandwidthConfigure(sbc)
end
return super
end
def appDisconnect(conn)
puts "Ruby appDisconnect"
if appScope == conn.getScope && @serverStream != nil
@serverStream.close
end
super
end
def toString
return "Ruby toString"
end
def setScriptContext(scriptContext)
puts "Ruby application setScriptContext"
end
def method_missing(m, *args)
super unless @value.respond_to?(m)
return @value.send(m, *args)
end
end
That is all that is required for a basic jruby application in red5.
More complicated example
Next I will explain a more complicated example that has defined services. I will use the oflaDemo as the example and will include a build file that will compile our application. As I said before, the purpose of this tutorial is to show you how to create and setup a basic application. I will go more into detail in later tutorials.
First we will need to create a new directory under red5/webapps. I will also refer to this one as red5Jruby. Once this is completed you will need to obtain the sources for the oflaDemo. If you complied red5 from the latest trunk version, they should be located in red5-trunk/webapps/oflaDemo. Now copy the contents of the oflaDemo directory into our new red5Jruby directory. Once that is completed you will then need to change the references to oflaDemo to red5Jruby in the configuration files. At this time you can also remove the handler and services definitions for java and the other scripting languages from the red5-web.xml.
You should now have a directory structure that looks like this:
red5/ ...webapps/ ......WEB-INF/ .........src/ #our application sources; both java and jruby ...........applications/ #our scripting sources ...........org/ .............red5/ ...............server/ .................webapp/ ...................oflaDemo/ #you will need to rename this directory to red5Jruby .....................Application.java .....................DemoService.java .....................IDemoService.java .....................DemoServiceImpl.java .........logback.xml .........build.xml .........build.properties
You will now need to change the following package definition to suit our new application in all of the java sources.
package org.red5.server.webapp.oflaDemo;
to
package org.red5.server.webapp.red5Jruby;
Also, you will need to change the logger definition in red5/webapps/red5Jruby/WEB-INF/logback.xml to match our application ie org.red5.server.webapp.red5Jruby.
Build sources
I pieced this together from red5/build.xml the comments should explain it pretty well
build.xml
<?xml version="1.0"?>
<project name="Complie Red5 webapp" basedir="." default="build">
<!-- Project properties -->
<property name="root.dir" value="../../../"/>
<property name="root.classes.dir" value="${root.dir}/bin"/>
<property name="root.lib.dir" value="${root.dir}/lib"/>
<property name="src.dir" value="src"/>
<property name="classes.dir" value="classes"/>
<property name="lib.dir" value="lib"/>
<property name="target.jar" value="red5Jruby.jar"/>
<!-- End Project properties -->
<!-- webapps Classpath -->
<path id="webapps.classpath">
<fileset dir="${root.dir}">
<filename name="red5.jar"/>
</fileset>
<fileset dir="${root.lib.dir}">
<filename name="*.jar"/>
</fileset>
<pathelement location="${root.classes.dir}"/>
</path>
<!-- End webapps Classpath -->
<!-- Clean webapp -->
<target name="clean" description="Cleans WEBAPP dir">
<echo message="Deleting the classes and lib directories...." />
<delete dir="${classes.dir}"/>
<delete dir="${lib.dir}"/>
</target>
<!-- End Clean webapp -->
<!-- Prepare webapp -->
<target name="prepare" depends="clean">
<echo message="Creating the classes and lib directories...." />
<mkdir dir="${lib.dir}"/>
<mkdir dir="${classes.dir}"/>
<mkdir dir="${classes.dir}/applications"/>
</target>
<!-- End Prepare webapp -->
<!-- Build webapp -->
<target name="build" depends="prepare">
<echo message="Compiling application sources...." />
<javac
sourcepath=""
srcdir="${src.dir}"
destdir="${classes.dir}"
classpathref="webapps.classpath"
optimize="true"
verbose="false"
fork="true"
nowarn="true"
deprecation="false"
debug="true"
compiler="modern"
source="1.6"
target="1.6"
/>
<echo message="Copying scripting sources..." />
<copy todir="${classes.dir}/applications">
<fileset dir="${src.dir}/applications"/>
</copy>
<copy todir="${classes.dir}" file="${src.dir}/logback.xml" overwrite="true"/>
<copy todir="${lib.dir}">
<fileset dir="${root.lib.dir}">
<include name="slf4j-api-1.4.3.jar"/>
<include name="logback-core-0.9.8.jar"/>
<include name="logback-classic-0.9.8.jar"/>
</fileset>
</copy>
</target>
<!-- End Build webapp -->
<!-- Create Jar -->
<target name="jar" description="Make Archive" depends="build">
<echo message="Creating Jar" />
<jar destfile="${lib.dir}/${target.jar}">
<fileset dir="${classes.dir}">
<include name="**"/>
</fileset>
</jar>
</target>
<!-- End Create Jar -->
</project>
You can use this same build file for future applications. However, you will need to change the target.jar property from red5Jruby.jar to yourAppName.jar
build.properties(not really used in this example)
# Base build properties # #javac options # http://ant.apache.org/manual/CoreTasks/javac.html # sun javac build.compiler=javac # jikes #build.compiler=jikes # generic compiler options build.verbose=false build.fork=true build.deprecation=false build.nowarn=true # optimize only works with a few compilers build.optimize=true # Change this var to build to a different Java version java.target_version=1.6 # jikes options build.compiler.emacs=false build.compiler.fulldepend=false build.compiler.pedantic=false
We are almost done now\! All we have left is to acutally build the application and start/restart the server. You can do this by navigating to red5/webapps/red5Jruby/WEB-INF and typing the following into the command prompt
ant jar
This will compile the application sources, create the required application directory structure and create a jar containing the contents of the newly created classes directory. At this point you should be able to restart the server and you should see the following in the terminal
Initializing ruby application Ruby appStart
Any suggestions or clarifications on any topics covered in this tutorial are more then welcome.
Enjoy, Thomas Johnson(tomfmason)
