JETZT ONLINE BESTELLEN
First Edition November 2008
ISBN 978-0-596-51980-3
222 Seiten
EUR29.00
Weitere Informationen zu diesem Buch
Inhaltsverzeichnis | Kolophon |
Inhaltsverzeichnis
- Chapter 1: Getting Started
- InhaltsvorschauJRuby is an open source implementation of the Ruby programming language for the Java Virtual Machine (JVM). It allows Ruby applications to be run within a Java Virtual Machine and interface with libraries written in either Java or Ruby. Although the JRuby project was initiated in 2001, interest in JRuby has grown significantly over the last few years, reflecting an overall growth in interest in Ruby sparked by the success of the Ruby on Rails framework. Sun has contributed to JRuby’s success by employing members of the core development team and providing support for JRuby in the NetBeans development environment, among other efforts. The website for the JRuby project is currently http://www.jruby.org.Ruby is a dynamic object-oriented programming language created by Yukihiro Matsumoto, known by the nickname Matz, in the mid-1990s. Ruby follows a style of versioning similar to the Linux kernel, where an even minor version number indicates a stable release and an odd minor version number indicates a development release. As a result, there are two current versions of Ruby: 1.8.6, released in March 2007, is the current stable release, and 1.9.0, released in December 2007, is the current development release. The standard Ruby interpreter is written in C. There are several alternate of the interpreter, including JRuby, IronRuby (for Microsoft’s .NET framework), and Rubinius. Ruby does not have a formal language specification; however, one is being developed through the wiki at http://spec.ruby-doc.org.As an object-orientated language, many of the underlying concepts of Ruby will be familiar to Java developers, even if the syntax is not. The biggest exception to this is Ruby’s support for blocks. In Ruby, a block is a grouping of code that gets passed to a method call. The receiving method can invoke the block any number of times and can pass parameters to the block. Support for a similar type of element, a closure, is being contemplated for inclusion in Java 7; there are several competing proposals and it is unclear which proposal, if any, will be adopted. contains a simple Ruby class demonstrating the two ways of defining a block in Ruby. The former syntax, using braces, is typically used to create a block for a single statement. The latter syntax, using theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Introduction
- InhaltsvorschauJRuby is an open source implementation of the Ruby programming language for the Java Virtual Machine (JVM). It allows Ruby applications to be run within a Java Virtual Machine and interface with libraries written in either Java or Ruby. Although the JRuby project was initiated in 2001, interest in JRuby has grown significantly over the last few years, reflecting an overall growth in interest in Ruby sparked by the success of the Ruby on Rails framework. Sun has contributed to JRuby’s success by employing members of the core development team and providing support for JRuby in the NetBeans development environment, among other efforts. The website for the JRuby project is currently http://www.jruby.org.Ruby is a dynamic object-oriented programming language created by Yukihiro Matsumoto, known by the nickname Matz, in the mid-1990s. Ruby follows a style of versioning similar to the Linux kernel, where an even minor version number indicates a stable release and an odd minor version number indicates a development release. As a result, there are two current versions of Ruby: 1.8.6, released in March 2007, is the current stable release, and 1.9.0, released in December 2007, is the current development release. The standard Ruby interpreter is written in C. There are several alternate of the interpreter, including JRuby, IronRuby (for Microsoft’s .NET framework), and Rubinius. Ruby does not have a formal language specification; however, one is being developed through the wiki at http://spec.ruby-doc.org.As an object-orientated language, many of the underlying concepts of Ruby will be familiar to Java developers, even if the syntax is not. The biggest exception to this is Ruby’s support for blocks. In Ruby, a block is a grouping of code that gets passed to a method call. The receiving method can invoke the block any number of times and can pass parameters to the block. Support for a similar type of element, a closure, is being contemplated for inclusion in Java 7; there are several competing proposals and it is unclear which proposal, if any, will be adopted. contains a simple Ruby class demonstrating the two ways of defining a block in Ruby. The former syntax, using braces, is typically used to create a block for a single statement. The latter syntax, using theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Installing JRuby
- InhaltsvorschauYou want to install JRuby.Download and extract the latest binary release from the JRuby website, http://www.jruby.org. Add the bin directory to the
PATHenvironment variable.Windows
The JRuby website makes binary releases available in both ZIP and TGZ file formats. Since Windows XP, Windows operating system software has included support for ZIP files. Commercial and open source software packages are available that include support for TGZ files, such as WinZip (http://www.winzip.com), 7-Zip (http://www.7-zip.org), and IZArc (http://www.izarc.com).It is not necessary to install JRuby in any particular location on your computer. My preference is to install Java libraries and executables in subdirectories ofC:\java. The results of extracting the binary for the latest release at the time of this writing, 1.1, can be seen in .
Figure : Extracted JRuby binary buildAfter extraction, JRuby is ready to be used. The simplest way to see JRuby in action is by runningjirb, JRuby’s version of Interactive Ruby (irb). Likeirb,jirballows you to execute Ruby statements and immediately see the results of each statement. JRuby includes both command-line and GUI versions ofjirbin the bin directory. The version, seen in , can be run by executing bin\jirb.bat; the GUI version, seen in , can be run by executing bin\jirb_swing.bat. In both figures, some trivial Ruby code has been executed. You can see that both the output of theputsmethod (Hello World) and its result (nil) have been output.
Figure : Command-line jirb
Figure : jirb GUIIf you launch either jirb.bat or jirb_swing.bat from Windows Explorer and all you see is a black window appear and then disappear quickly, the likely cause is that you do not have theJAVA_HOMEenvironment variable set, or the value of this environment variable is incorrect. To set environment variables in Windows, use the System control panel’s Advanced tab.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Managing Packages with RubyGems
- InhaltsvorschauYou want to install Ruby on Rails or other Ruby packages for use with JRuby.Use the RubyGems support built into JRuby. Once JRuby has been installed, you can immediately start using RubyGems to manage Ruby packages by running the gem script included in JRuby’s bin directory. To install a package, run:
$ gem install packagenameFor example, to install the Ruby on Rails web framework, use:$ gem install rails
RubyGems is the standard package management and distribution system for Ruby packages. There are thousands of packages, referred to as gems, available through the default RubyGems repository at http://gems.rubyforge.org. Although some gems are specific to the C Ruby implementation or JRuby, most are compatible with any Ruby implementation.Common RubyGems commands includeinstall,query,update,uninstall, andrdoc. The full list can be output by using thehelpcommand:$ gem help commands GEM commands are: build Build a gem from a gemspec cert Manage RubyGems certificates and signing settings check Check installed gems cleanup Clean up old versions of installed gems in the local repository contents Display the contents of the installed gems dependency Show the dependencies of an installed gem environment Display information about the RubyGems environment fetch Download a gem and place it in the current directory generate_index Generates the index files for a gem server directory help Provide help on the 'gem' command install Install a gem into the local repository list Display all gems whose name starts with STRING lock Generate a lockdown list of gems mirror Mirror a gem repository outdated Display all gems that need updates pristine Restores installed gems to pristine condition from files located in the gem cache query Query gem information in local or remote repositories rdoc Generates RDoc for pre-installed gems search Display all gems whose name contains STRING server Documentation and gem repository HTTP server sources Manage the sources and cache file RubyGems uses to search for gems specification Display gem specification (in yaml) uninstall Uninstall gems from the local repository unpack Unpack an installed gem to the current directory update Update the named gems (or all installed gems) in the local repository which Find the location of a library For help on a particular command, use 'gem help COMMAND'. Commands may be abbreviated, so long as they are unambiguous. e.g., 'gem i rake' is short for 'gem install rake'.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using Both Ruby and JRuby
- InhaltsvorschauYou have Ruby and JRuby installed on the same computer and want to ensure that a Ruby script is processed by the correct interpreter.Use the
-Scommand-line argument for the ruby and jruby executables. For example, RubyGems is traditionally invoked with a command like:gem install rails
Instead, use:$ jruby –S gem install rails
or:$ ruby –S gem install rails
Popular Ruby packages such as Rake, Ruby on Rails, and RubyGems include their own executable Ruby scripts that most guides, both online and print, instruct you to invoke directly. Whether these scripts run with Ruby or JRuby depends on how you’ve configured thePATHenvironment variable, which platform you use, and what package is involved. Because there are so many variables, this recipe prescribes using a single, consistent method, passing the script name through the-Scommand-line argument to either the ruby or jruby executables.The-Scommand-line option instructs Ruby and JRuby to load a script file from thePATH. JRuby includes its own copies of the Rake and RubyGems scripts in bin/rake and bin/gem, respectively, but they are verbatim copies of the original scripts. As a result, it doesn’t matter which version of the script you execute, only the interpreter with which you execute it.This advice is particularly significant in the context of the RubyGems script, gem. To create a new Rails application, you could run either:$ ruby –S rails sampleapp
or:$ jruby –S rails sampleapp
and see the same result. However, running:$ ruby –S gem install rails
and:$ jruby –S gem install rails
will install the Rails gem in two different locations. You can see this by passingenvironmentto the gem script:$ ruby -S gem environment RubyGems Environment: - RUBYGEMS VERSION: 1.0.1 (1.0.1) - RUBY VERSION: 1.8.5 (2007-09-24 patchlevel 114) [i386-linux] - INSTALLATION DIRECTORY: /usr/lib/ruby/gems/1.8 - RUBY EXECUTABLE: /usr/bin/ruby - RUBYGEMS PLATFORMS: - ruby - x86-linux - GEM PATHS: - /usr/lib/ruby/gems/1.8 - GEM CONFIGURATION: - :update_sources => true - :verbose => true - :benchmark => false - :backtrace => false - :bulk_threshold => 1000 - REMOTE SOURCES: - http://gems.rubyforge.org $
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Sharing RubyGems
- InhaltsvorschauYou already have a number of RubyGems installed and want to use those gems from JRuby without reinstalling the gems.Set the
GEM_HOMEenvironment variable to your existing RubyGems installation location. This value can be seen in the output ofgem environment, where it is referred to as the installation directory:$ ruby -S gem environment | grep -i 'installation directory' - INSTALLATION DIRECTORY: /usr/lib/ruby/gems/1.8 $ export GEM_HOME=/usr/lib/ruby/gems/1.8 $ jruby -S gem environment | grep -i 'installation directory' - INSTALLATION DIRECTORY: /usr/lib/ruby/gems/1.8
Whereas some RubyGems are implemented entirely in Ruby, many are implemented in a combination of Ruby and C (or, in a growing number of cases, Ruby and Java). Pure-Ruby gems can be installed using either JRuby or C Ruby. However, those in a mixture can only be installed using a compatible interpreter. The list of supported platforms for each interpreter can be seen in the output ofgem environment. Because the RubyGems runtime knows this list of supported platforms, it is possible to mix gems supporting different platforms in the same directory; the runtime will select the appropriate libraries.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Referencing Java Classes from Ruby
- InhaltsvorschauYou want to write Ruby code that uses one or more Java classes.First, you need to tell JRuby that you will be referencing Java classes from your Ruby code. Do this by including an
includedeclaration at the top of your Ruby file:include Java
The syntax for referencing a specific Java class depends on the package in which the class resides. For packages starting withjava,javax,org, andcom, you can simply the fully qualified class name or use animportstatement, as shown in .Example . Creating a Java TreeMap from Ruby# using the fully-qualified class name map = java.util.TreeMap.new # using an import statement import java.util.TreeMap map = TreeMap.new
For classes that reside in a package that does not begin withjava,javax,org, orcom, as well as classes in the default package, you need to use theinclude_classfunction, as in .Example . Referencing a Java class with include_classinclude_class 'EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap' map = ConcurrentHashMap.new
Theinclude_classfunction can also handle classes in packages starting withjava,javax,org, andcomif you don’t want to switch back and forth.Theinclude_classfunction can also be used to create aliases in cases where a Java class name conflicts with a Ruby class name. To do this, pass a block to the function. aliases the JavaStringclass asJStringso that it does not conflict with Ruby’sStringclass.Example . Creating an alias to avoid class name conflictsinclude Java include_class 'java.lang.String' do |package,name| "JString" end p JString.new("A quick brown fox").indexOf("brown")You can pass multiple class names to theinclude_classas a list. In this case, you could provide the appropriate alias using acasestatement, as seen in .Example . Aliasing multiple classes with caseinclude_class ['java.lang.String','java.lang.Integer'] do |package,name| case name when "String" "JString" when "Integer" "JInteger" end endEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Converting a Ruby Array into a Java Array
- InhaltsvorschauYou need to pass a Ruby array to a method that accepts a Java array of a specific type.Call the Ruby array’s
to_javamethod with an argument specifying the component type of the array. For example, creating an array ofjavax.xml.transform.stream.StreamSourceobjects would be done like this:import javax.xml.transform.stream.StreamSource cnn = StreamSource.new "http://rss.cnn.com/rss/cnn_topstories.rss" mtv = StreamSource.new "http://www.mtv.com/rss/news/news_full.jhtml"
# Call a transforming Java API. This method would have been declared # with this signature: # public String transform(StreamSource[] sources) p transformer.transform([cnn,mtv].to_java(StreamSource))
Primitives, as well asjava.lang.String, have Ruby symbols assigned to them. For , to create an array ofintprimitives:[1,2,3,4,5,6,7,8,9,10].to_java(:int)
This JRuby feature is critical for accessing Java APIs. For example, calling a method through Java Management Extensions (JMX) involves passing two arrays to theinvoke()method ofjavax.management.MBeanServer, one ofObjectinstances, storing the method parameters, and one ofStringinstances, storing the method signature. To callinvoke()from JRuby, you would do something like this:brokerName = ObjectName.new('org.apache.activemq:BrokerName=localhost,Type=Broker') params = ["MyQueue"].to_java() signature = ["java.lang.String"].to_java(:string) server.invoke(brokerName, 'addQueue', params, signature)Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Adding JAR Files to the Classpath
- InhaltsvorschauYou want to reference a Java class which is contained in a JAR file that isn’t already included in your classpath.Call Ruby’s
requiremethod with the path to the JAR file. This path can be relative to the current working directory:require 'lib/commons-logging-1.1.jar'
or an absolute path:require '/opt/java/commons-logging/bin/commons-logging-1.1.jar'
If you are using Windows, this path can have either type of slash:require 'c:\java\commons-logging-1.1\bin\commons-logging-1.1.jar' # or require 'c:/java/commons-logging-1.1/bin/commons-logging-1.1.jar'
Although this is an extremely useful feature of JRuby, it should be used with caution, especially if you use absolute paths that are platform- and installation-specific. Relative paths can seem like a better solution, but are actually more limiting, as they are evaluated from the current working directory, not the script’s directory. Yet all is not lost.An interesting aspect of this feature of JRuby is that the JAR file is added to the classpath dynamically, while the application is running. This allows you to use Ruby’s string interpolation functionality to create absolute paths. includes a method that creates a path to a JAR file in a local Maven repository.Example . Creating a JAR file path dynamically# Set the HOME environment variable if USERPROFILE is set ENV['HOME'] = ENV['USERPROFILE'] if (ENV['USERPROFILE']) def require_from_maven(group,artifact,version) maven_path = "#{group}/#{artifact}/#{version}/#{artifact}-#{version}.jar" require "#{ENV['HOME']}/.m2/repository/#{maven_path}" endApplication code could userequireto include this script and then use therequire_from_mavenmethod to reference a specific JAR file:require 'require_from_maven' require_from_maven "commons-logging", "commons-logging", "1.1"
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Extending a Java Class in Ruby
- InhaltsvorschauTo use a Java API, you need to create a Ruby class that subclasses a Java class.Use the standard Ruby superclassing operator
<and specify the Java class you want to subclass. shows a Ruby class that extends the JavaThreadclass and overrides therun()method.Example . Subclassing a Java class in Rubyinclude Java class MyThread < java.lang.Thread def run puts 'hello world' end end MyThread.new.startThe fact that the same syntax is used to extend both Java and Ruby classes is an important design feature of JRuby, as it furthers the seamless integration between the two languages.One notable exception to this recipe is classes that use Java 5 generics. Currently, these cannot be subclassed with Ruby classes.Abstract Java classes can also be extended by Ruby classes. Examples and show an example of an abstract Java class and a concrete Ruby class that extends the former. Thehello()method, declared abstract in the Java class, is implemented in the Ruby class.Example . An abstract Java classpackage org.jrubycookbook.ch01; public abstract class AbstractElement { public abstract void hello(); public void sayHello(int count) { for (int i = 0; i < count; i++) { hello(); } } }Example . Ruby class that subclasses an abstract Java classinclude Java import org.jrubycookbook.ch01.AbstractElement class RubyElement < AbstractElement def hello puts 'hello world' end end RubyElement.new.sayHello 5Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Implementing a Java Interface in Ruby
- InhaltsvorschauTo use a Java API, you need to create a Ruby class that implements a Java interface.Create your class with method names that match the names in the Java interface. As of version 1.1, JRuby runtime supports the use of duck typing for implementing Java . Duck typing, seen in many dynamic languages, including Ruby, means that the type of an object is determined based on the methods implemented by the object. shows this technique in action as a new Java thread by passing the an object that implements the
java.lang.Runnableinterface. TheHelloThreadclass contains a zero-argumentrunmethod that corresponds to the method defined injava.lang.Runnable. JRuby requires no additional type information in theHelloThreadclass to instantiate theThreadobject.Example . Ruby implementation of a Java interfaceinclude Java class HelloThread def run puts 'hello world' end end java.lang.Thread.new(HelloThread.new).startThere are few situations when duck typing isn’t sufficient and you’ll need to provide additional type information to the interpreter. One case is when a duck-typed JRuby object is passed as an argument to an overloaded Java method. Without additional Java type information, the JRuby interpreter doesn’t definitively know which method to execute. The solution is to use Ruby’sincludestatement to assign an explicit Java interface to a Ruby class. This provides the JRuby interpreter with enough information about the object to execute the correct method. In , theHelloThreadclass is assigned theRunnableinterface. As a result, JRuby calls the desiredexec()method andrunnableis output to the console.Example . Declaring Java interfaces in JRubyBalloon.java public interface Balloon { void pop(); } Bubble.java public interface Bubble { void pop(); } Child.java public class Child{ public void give(Bubble bubble){ System.out.println("Thanks for the bubble."); bubble.pop(); } public void give(Balloon balloon){ System.out.println("Thanks for the balloon."); balloon.pop(); } }
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Opening Java Classes with JRuby
- InhaltsvorschauYou want to add methods to a Java class.Import the Java class so that the class can be referenced, and add methods as you would to any Ruby class.In Ruby, class definitions are never finalized; new methods can be added at any time. This is perhaps one of the most significant differences between Java and Ruby. In Java, class definitions are tightly bound to filenames and directory structures. The complete definition of the Java class
java.util.HashMapwill be found in a file named /java/util/HashMap.class. In Ruby, no such relationship exists and classes can be defined across multiple source files. With JRuby, it’s possible to apply this language feature to Java classes. shows a simple example of enhancing thejava.util.HashMapclass with a method namedis?.Example . Adding a method to HashMapinclude Java import java.util.HashMap class HashMap def is?(key,value) value == get(key) end endAs you can see in this example, within the new method we can call methods defined by the original Java class. Once this code is executed, JRuby instances of theHashMapclass, including those already created, will have this new method. This even applies to instances of the class created by Java code. Examples and contain a Java class that creates aHashMapobject and Ruby code that opens theHashMapclass and exercises the new method.Example . A simple class to generate a HashMap objectpackage org.jrubycookbook.ch01;
import java.util.*; public class MapMaker { public static Map makeMap() { Map m = new HashMap(); m.put("k1", "v1"); m.put("k2", "v2"); return m; } }Example . Applying open class semantics to an instance created with Java codeinclude Java import java.util.HashMap import org.jrubycookbook.ch01.MapMaker h = MapMaker.makeMap() class HashMap def isNot?(key,value) value != get(key) end end puts (h.isNot? 'k1', 'v1') puts (h.isNot? 'k2', 'v3')However, any added methods are only visible to the JRuby runtime. If you were to pass an instance of this modifiedEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Setting Up Eclipse for JRuby Development
- InhaltsvorschauYou use the Eclipse Integrated Development Environment (IDE) for Ruby development and want to run Ruby code easily with the JRuby interpreter.When using the Ruby Development Tools (RDT) plugin, create a new Ruby VM definition that is pointed at your JRuby installation location and whose type is set to
JRuby VM. When using the Dynamic Language Toolkit (DLTK) plugin, create a new Ruby interpreter definition that references the JRuby launch script: bin\jruby.bat (for Windows) or bin/jruby (for Linux and Mac OS X) from your JRuby installation.Both RDT and DLTK can be configured to work with multiple Ruby interpreters. RDT has a specific setting available for the JRuby interpreter, whereas DLTK simply treats JRuby as a generic Ruby interpreter.RDT
RDT, available from http://rubyeclipse.sourceforge.net, supports configuration of Ruby interpreters based on the installation directory. To add JRuby as an interpreter, open the Preferences dialog and locate the Installed Interpreters page. Click the Add button to open the Add RubyVM dialog (seen in ). In this dialog, select JRuby VM as the RubyVM type and select the JRuby installation directory as the RubyVM home directory. You can also override the display name with something more user-friendly. Once you’re satisfied with the settings, click OK.
Figure : RDT Add RubyVM dialogDLTK
The Dynamic Language Toolkit project, hosted at http://www.eclipse.org/dltk, is a broad project sponsored by the Eclipse Foundation to provide general support for languages in the Eclipse development environment. Currently, support is available through the DLKT project for Ruby, TCL, and Python. The DLTK Ruby plugin does not make a distinction between a standard Ruby interpreter and the JRuby interpreter. Just as when configuring RDT, open the Preferences dialog and locate the page. Click the Add button to open the “Add interpreter” dialog, seen in . Select theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Setting Up NetBeans for JRuby Development
- InhaltsvorschauYou want to develop Ruby applications with NetBeans.Download NetBeans 6.5 from http://www.netbeans.org and run the installer. NetBeans is available in a variety of bundles; both the Ruby and All bundles include support for Ruby development. In addition to Ruby, the All bundle includes support for Java, Web, Mobile, and C/C++, as well as both Apache Tomcat and Sun GlassFish application servers.If you are already using NetBeans 6.5, Ruby support can be installed using the Plugins dialog, seen in . This plugin adds new NetBeans project types for Ruby and Rails, graphical debuggers for Ruby and Rails, a Ruby Code Editor, and a RubyGems client.
Figure : Installing the NetBeans Ruby plugin with the Plugins dialogOnce the Ruby plugin has been installed, use the Ruby page in the Ruby Platforms dialog seen in to manage the Ruby runtimes used by your projects. Notice the options to add new runtimes or modify an interpreter’s gem repository location and debug level. By default, your Ruby project will use the JRuby runtime shipped with the Plugin, but you can assign a specific Ruby Platform to your application by using the project’s properties dialog.After several years of playing second fiddle to Eclipse, Sun has recently made some significant investments in the NetBeans project, and it shows—nowhere more so than in the Ruby plugin. The NetBeans Ruby Code Editor includes syntax highlighting, code coloring, refactoring support, and powerful code completion capabilities. The code completion functionality can be seen in . The editor displays a list of possible methods in a small window, including built-in and user-defined Ruby classes. Hitting the space bar at this point inserts the complete name into the editor.
Figure : NetBeans Ruby Platform Manager dialog
Figure : NetBeans Ruby code completionYou can also change the editor’s font and highlighting colors or change the key bindings to match your personal preferences. Configuration is done in the Options dialog seen in . Choose the Fonts & Colors tab and select a Profile from the list. OS X Ruby developers might be interested in a TextMate theme, Aloha (Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Platform Detection in a JRuby Application
- InhaltsvorschauYou would like to detect the platform used by the Ruby runtime and customize your code for a JRuby runtime environment.You can detect whether your application is running in JRuby by evaluating the
JRUBY_VERSIONsystem variable. This value will always be defined in a JRuby application but never in any other Ruby runtime. Thegenerate_random_numbermethod in uses the random number generator from the JavaMathclass in a JRuby ; , the application calls Ruby’srandmethod.Example . JRuby platform detectionclass DetectionExample def generate_random_number if(defined?(JRUBY_VERSION)) require 'java' puts 'executing java method' java.lang.Math.random else puts 'executing ruby method' rand(0) end end end d = DetectionExample.new puts d.generate_random_numberTheRUBY_PLATFORMvariable has information about the runtime environment and is set tojavain JRuby. It was used with early versions of JRuby for platform detection, but theJRUBY_VERSIONvariable was later added to identify unequivocally that the code was running in JRuby and not another Ruby interpreter written in Java. The new variable also opened up the possibility for JRuby version-specific code.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 2: JRuby on Rails
- InhaltsvorschauSince its introduction in mid-2004, the Ruby on Rails web framework has rapidly gained a significant following within the web development community. It is the single largest factor in the overall increase in interest in the Ruby programming language. Likewise, JRuby’s ability to run Rails applications inside a Java Virtual Machine has been a driver for interest in JRuby. This chapter explores some techniques for running Rails applications in a Java environment.Ruby on Rails is a framework for developing web applications that follows the model-view-controller (MVC) architecture. The notion of Convention over Configuration is stressed throughout the framework, most prevalently within ActiveRecord, the object-relational-mapping (ORM) subsystem. ActiveRecord uses database metadata (table and column names) to dynamically define domain classes. Using ActiveRecord, simply adding a new column to a database table automatically adds a corresponding field to the related domain class.Running Rails applications on JRuby provides several advantages:
- Rails applications can be deployed into existing Java EE containers such as Tomcat, JBoss, and GlassFish.
- Through Java Database Connectivity (JDBC), Rails applications can be connected to virtually any database for which a JDBC driver exists.
- Rails applications can access container-managed database connection pools through Java Naming and Directory Interface (JNDI).
In short, the combination of JRuby and Rails produces an enterprise-friendly package that blends seamlessly into an existing Java EE environment. From an application ’s perspective, the Rails application is just another Java EE web application; if JNDI data sources are used, the application deployer never even needs to look at Rails configuration files.Beyond JRuby, the primary library that provides the bridge between the Java EE container and Rails is called JRuby-Rack. JRuby-Rack is basically a Java servlet filter that dispatches requests to a Rails application running inside JRuby. JRuby-Rack creates a pool of JRuby runtime instances. Configuration of the JRuby-Rack servlet is discussed in . Early approaches to Java EE packaging and servlet integration used the GoldSpike project, but that code has been deprecated and replaced by JRuby-Rack.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Introduction
- InhaltsvorschauSince its introduction in mid-2004, the Ruby on Rails web framework has rapidly gained a significant following within the web development community. It is the single largest factor in the overall increase in interest in the Ruby programming language. Likewise, JRuby’s ability to run Rails applications inside a Java Virtual Machine has been a driver for interest in JRuby. This chapter explores some techniques for running Rails applications in a Java environment.Ruby on Rails is a framework for developing web applications that follows the model-view-controller (MVC) architecture. The notion of Convention over Configuration is stressed throughout the framework, most prevalently within ActiveRecord, the object-relational-mapping (ORM) subsystem. ActiveRecord uses database metadata (table and column names) to dynamically define domain classes. Using ActiveRecord, simply adding a new column to a database table automatically adds a corresponding field to the related domain class.Running Rails applications on JRuby provides several advantages:
- Rails applications can be deployed into existing Java EE containers such as Tomcat, JBoss, and GlassFish.
- Through Java Database Connectivity (JDBC), Rails applications can be connected to virtually any database for which a JDBC driver exists.
- Rails applications can access container-managed database connection pools through Java Naming and Directory Interface (JNDI).
In short, the combination of JRuby and Rails produces an enterprise-friendly package that blends seamlessly into an existing Java EE environment. From an application ’s perspective, the Rails application is just another Java EE web application; if JNDI data sources are used, the application deployer never even needs to look at Rails configuration files.Beyond JRuby, the primary library that provides the bridge between the Java EE container and Rails is called JRuby-Rack. JRuby-Rack is basically a Java servlet filter that dispatches requests to a Rails application running inside JRuby. JRuby-Rack creates a pool of JRuby runtime instances. Configuration of the JRuby-Rack servlet is discussed in . Early approaches to Java EE packaging and servlet integration used the GoldSpike project, but that code has been deprecated and replaced by JRuby-Rack.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Installing and Setting Up Rails
- InhaltsvorschauYou want to run Ruby on Rails with JRuby.Install the latest Ruby on Rails gem with this command:
$ jruby –S gem install rails
If you’re running Rails 2.x, it is recommended you install thejruby-opensslgem to take advantage of all the security features and session storage options. This gem is the Java implementation of theopensslgem:$ jruby –S gem install jruby-openssl
Now create your Rails application with JRuby:$ jruby –S rails MyKillerApplication
Test your new Rails application:$ cd MyKillerApplication $ jruby ./script/server
Open your browser and go to http://localhost:3000. You should see the ubiquitous Rails welcome screen, shown in .
Figure : Ruby on Rails welcome screenThe next step is to configure Rails to connect to your database. The JRuby team has made this easy by allowing Rails to use the familiar and widely supported Java JDBC drivers. You first need to install theactiverecord-jdbc-adaptergem:$ jruby –S gem install activerecord-jdbc-adapter –y –-no-ri –-no-rdoc
The gem allows the Rails database management system, ActiveRecord, to use a JDBC connection or connection pool for database access. This can be conveniently configured in the standard Rails database.yml file by specifying the JDBC URL or a JNDI address. The example database.yml in is configured to use a JDBC connection in the development environment and container-providedjavax.sql.DataSourcewith the JNDI namejava:comp/env/jdbc/rails_dbin the production environment. Remember to include the JDBC driver in your classpath when using the standardjdbcadapter.Example . Example database.yml using JDBCdevelopment: adapter: jdbc url: jdbc:mysql://localhost:3306/jrubycookbook_development driver: com.mysql.jdbc.Driver username: jruby password: cookbook production: adapter: jdbc jndi: java:comp/env/jdbc/rails_db driver: com.mysql.jdbc.Driver
The JRuby Extras project contains a set of database adapters for the most commonly used open source databases by Java developers, including h2, JavaDB (Derby), MySQL, HSQLDB (Hypersonic), and Postgres. The adapter gems give you the option of using ordinary Rails database configuration values in yourEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Packaging Rails As a Java EE Web Application
- InhaltsvorschauYou want to package a Rails app as a Java EE web application for deployment onto a standard Java EE web container.Use Warbler to package your Rails application as a WAR file. Start by installing the gem:
$ jruby –S gem install warbler
This gem adds thewarblecommand, which allows you to create, configure, and clean up the WAR file. All Warbler commands should be executed in the root directory of your Rails application. Start by creating a Warbler configuration file with this :$ jruby –S warble config
The new configuration file is written to config/warble.rb. This file allows you to set most of the necessary options for building your WAR and determining how Rails will run in the web container. Open warble.rb and configureconfig.webxml.rails.envto the of your Rails deployment. Next, add all the gems used by your web application to theconfig.gemshash except for therailsgem. Rails is included in the default hash. An example warble.rb file showing these options can be seen in .Example . Example Warbler configuration file# Value of RAILS_ENV for the webapp config.webxml.rails.env = 'development' # List of all your application's gems config.gems << "activerecord-jdbcmysql-adapter" config.gems << "jruby-openssl"
You’re ready to create a WAR file by running this command:$ jruby –S warble war
This generates a WAR file named the Rails project home directory name by default. For example, if our Rails project was in the MyKillerApplication folder, the WAR file would be named MyKillerApplication.war. This WAR file can then be deployed into your Java EE container using the container’s deployment process.Warbler is a Ruby gem for packaging a Rails application as a Java EE web application. It is built on the Rake build system and JRuby-Rack servlet adapter. The default implementation of the adapter uses a servlet filter that allows the container’s default servlet to process the static content rather than Rails. Early versions of Warbler used the GoldSpike servlet, but the GoldSpike project has been deprecated and has been replaced by JRuby-Rack. The JRuby-Rack library includes a stub version of the GoldSpike servlet in order to maintain compatibility with legacy GoldSpike applications.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using an External Gem Repository with a Web Application
- InhaltsvorschauYou don’t want to package your gems into your web application but want to use a gem repository on the filesystem.There are a few situations where you might want to use a different gem repository outside of the default JRuby runtime’s repository. This could useful when you are maintaining a shared set of gems that are being accessed by both C Ruby and JRuby. You can configure your web application to use a separate gem repository through the
gem.pathorgem.homesystem properties. These properties can be set in the WAR’s file, web.xml, or through a system property when the container is started, as seen in .Example . Sample web.xml setting the gem.path context parameter<context-param> <param-name>gem.path</param-name> <param-value>C:\projects\jruby\jruby-1.1\lib\ruby\gems</param-value> </context-param> <!-- Alternatively <context-param> <param-name>gem.home</param-name> <param-value>C:\projects\jruby\jruby-1.1\lib\ruby\gems</param-value> </context-param>-->You can also set thegem.pathin the startup parameters for the servlet container:$ java -jar start.jar etc/jetty.xml \ –Dgem.path="C:\projects\jruby\jruby-1.1\lib\ruby\gems"
- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Configuring the JRuby-Rack Servlet
- InhaltsvorschauYou want to configure the number of JRuby runtimes in the container.Edit the values in warble.rb to your desired settings:
config.webxml.jruby.min.runtimes = 2 config.webxml.jruby.max.runtimes = 4
Generate the Rails WAR file:$ jruby –S warble war
The JRuby-Rack servlet allows Rails to integrate into most Java EE containers. Because many parts of Rails prior to version 2.2 are not threadsafe, the runtime cannot be used to simultaneously process multiple requests. JRuby-Rack utilizes a configurable pool of JRuby runtimes that are dispatched for each incoming Rails request. The number of simultaneous requests that can be processed is limited by the number of available runtimes. Any additional requests will block and must wait for a runtime to become free. It’s highly advised that you set a maximum number of runtimes for your production application because by default Warbler will allow for an unlimited number of runtimes. These are all the configuration options:config.webxml.jruby.max.runtimes- This sets the most number of active JRuby runtimes in the pool, which determines the maximum number of simultaneous requests. Default value is unlimited.
config.webxml.jruby.min.runtimes- This determines the number of “warm” runtimes or the minimum number of runtimes in the pool. It also dictates how many instances when the application is started. The default value is none.
config.webxml.jruby.runtime.initializer.threads- This sets how many threads will be used to initialize the JRuby runtimes in the pool. The value will vary based on the number of runtimes you intend to use at startup and the initialization time of the pool. The default value is 4.
config.webxml.jruby.runtime.timeout.sec- This sets how long in milliseconds an incoming request should wait for a JRuby runtime before returning an error. The default is 30 seconds.
The CPU, memory, and system resources of the host machine generally determine the number of maximum and minimum idle runtimes. The JRuby runtime is a memory-intensive application, so it is recommended to run the application with a generous amount of both permanent generation (PermGen) and heap memory. This is especially true when using a large number of runtimes.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Packaging Rails with a JNDI DataSource
- InhaltsvorschauYou want to configure your Rails application to access a JDBC DataSource through Java Naming and Directory Interface (JNDI).Install the
activerecord-jdbc-adaptergem (as in ) and edit your database.yml file. The JNDI lookup service is provided by thejdbcadapter gem. Set thedrivervalue to your database’s JDBCDriverclass and add the JNDI location of the JDBC DataSource. This example database.yml file is configured to use a JDBC factory for a MySQL database:development: adapter: jdbc jndi: java:comp/env/jdbc/rails_db driver: com.mysql.jdbc.Driver
Use Warbler to package your Rails application (see ). Edit your warble.rb file and set the resource reference name of your JNDI DataSource in the configuration file:# JNDI data source name config.webxml.jndi = 'jdbc/rails_db'
Repackage the WAR by running Warbler’swartask:$ jruby –S warble war
Thewarorwar:webxmltasks create or overwrite an existing Java EE web deployment descriptor file, /WEB-INF/web.xml, in your Warbler staging area, tmp/war. Both tasks add theresource-refdefinition and all the required information for a new JDBC . Here is an example web.xml for Rails application using a JNDI DataSource referenced atjdbc/rails_db:<resource-ref> <res-ref-name>jdbc/rails_db</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref>You always have the option of manually editing the files and values generated by Warbler. If you choose to edit the web.xml descriptor file by defining new DataSources or setting configuration values or references, you can use Warbler’swar:jartask to skip the file generation steps and package all the files in the staging folder into the application WAR file:$ jruby –S warble war:jar
- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Deploying Rails on Tomcat
- InhaltsvorschauYou want to deploy a Rails Java EE application using Apache Tomcat.Package your Rails application as a Java EE WAR (see ). Place the resulting WAR file in the Tomcat’s webapps directory. If you are using one of the database-specific JDBC adapter gems, you’re ready to start Tomcat. If your Rails application is using the regular
jdbcadapter, include the JDBC adapter’s JAR file in your classpath or copy the JAR file into $TOMCAT_HOME/common/lib.Be sure to set theJAVA_HOMEenvironment variable to the folder where you’ve installed Java. A performance tip is to start Tomcat with the-serverflag. It is also advisable to set constraints for the heap and PermGen so potential memory leaks do not consume all the resources on the server and cripple the machine.Windows
> set JAVA_HOME=c:\Program Files\Java\jdk1.5.0_12 > set CATALINA_OPTS=-server –Xms512m –Xmx1024m -XX:PermSize=256m \ –XX:MaxPermSize=512m > catalina.bat start
Linux and OS X
$ export JAVA_HOME=/usr/java/jdk1.5.0_12 $ export CATALINA_OPTS='-server –Xms512m –Xmx1024m -XX:PermSize=256m –XX:MaxPermSize=512m' $ ./catalina.sh start
It is important to understand JRuby’s memory usage so that you can properly tune your applications. The JVM has separate memory spaces. One, known as permanent generation (PermGen), is reserved for internal class file representations and VM data structures. The other, heap, is the more known and is typically used to store the data represented in those classes. A lot of JRuby success is owed to the ability to work around the rules of a statically compiled language (i.e., Java) by generating classes and data structures at runtime. The cost of this approach is that in some cases JRuby may need to generate a large number of objects and these objects are all stored in the permanent generation space and not the heap. Consider the case of Rails, where a single request could generate hundreds of JRuby objects. This usage of PermGen is many times the default case, so the default VM memory setting is often insufficient. The JRuby team has made strides in alleviating the problem, such as allowing JRuby runtimes to share PermGen space, but you should take a cautious approach by setting initial and maximum values for your PermGen and heap, especially for production applications.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Deploying Rails on JBoss
- InhaltsvorschauYou want to deploy a Rails application on the JBoss Application Server.Package your Rails application as a Java EE WAR (see ). Copy the application WAR into $JBOSS_HOME\server\default\deploy, the default JBoss deployment folder, or any server-specific deployment directory you have defined in the JBoss configuration files. If you are using the non-database-specific
jdbcadapter for connecting to your database, be sure to include the JDBC JAR in the classpath. You can also copy the JDBC JAR into $JBOSS_HOME\server\default\lib if you’re running the default server.Be sure to start the application server with the–serverflag and set some expected size for your heap and permanent generation, PermGen, memory space. Typically this is done through theJAVA_OPTSenvironment variable.Windows
> SET JAVA_HOME=c:\Program Files\Java\jdk1.5.0_12 > SET JAVA_OPTS=-server –Xms512m –Xmx1024m -XX:PermSize=256m –XX:MaxPermSize=512m > run.bat
Linux and OS X
$ export JAVA_HOME=/usr/java/jdk1.5.0_12 $ export JAVA_OPTS='-server –Xms512m –Xmx1024m -XX:PermSize=256m\ –XX:MaxPermSize=512m' $ ./run.sh
If you are using a JNDI resource for your Rails database connection, you will need to create the DataSource in the JBoss server. The JBoss distribution provides sample configurations for most of the popular databases in the examples folder, $JBOSS_HOME\docs\examples\jca. This a great starting place for simple database setups. After you have edited the file, you can easily deploy a DataSource in JBoss by placing the file in the deployment directory. $JBOSS_HOME\server\default\deploy is the deployment folder for the default server.If you’re running a MySQL database, change the<jndi-name>MySqlDS</jndi-name>configuration parameter to the name of your DataSource,rails_dbin this example. Set the rest of database information in the configuration file with the appropriate values for your database. shows an edited mysql-ds.xml DataSource definition for the example application. Note that theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Deploying Rails on Jetty
- InhaltsvorschauYou want to deploy a Rails application on the Jetty Servlet container.Package your Rails application as a Java EE WAR (see ). If you’ve defined a JDBC connection with the
jdbcadapter or using a JNDI DataSource, remember to include the JDBC adapter in your classpath or copy the JAR into $JETTY_HOME/lib to make it available to any deployed web applications. Place the WAR into Jetty’s $JETTY_HOME/webapp folder. Start the server with the–serverVM option and heap and PermGen values:$ java -server –Xms512m –Xmx1024m -XX:PermSize=256m –XX:MaxPermSize=512m\ -jar start.jar etc/jetty.xml
If you would like to use a JNDI resource for your Rails database connection, start by defining a DataSource in your WAR. Create a file called jetty-env.xml in the WEB-INF folder of your staging area. shows a jetty-env.xml configuration for a MySQL database.Example . Sample jetty-env.xml file<?xml version="1.0"?> <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd"> <Configure class="org.mortbay.jetty.webapp.WebAppContext"> <New id="rails_db" class="org.mortbay.jetty.plus.naming.Resource"> <Arg>jdbc/rails_db</Arg> <Arg> <New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource"> <Set name="Url">jdbc:mysql://localhost:3306/jrubycookbook_development</Set> <Set name="User">root</Set> <Set name="Password">password</Set> </New> </Arg> </New> </Configure>Repackage your application with Warbler and deploy to Jetty. Jetty’s JNDI module is not enabled in the standard webapps deployment folder by default, so either update $JETTY_HOME/etc/jetty.xml to enable JNDI for this directory or configure Jetty to use an alternative directory. It is the Jetty convention to install applications that require JNDI into the webapps-plus directory:$ copy MyKillerApplication.war $JETTY_HOME/webapps-plus
Jetty supplies a convenient $JETTY_HOME/etc/jetty-plus.xml file, which configures Jetty to use that folder. Run this command from the Jetty home directory to start Jetty with JNDI support:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Deploying Rails with jetty_rails
- InhaltsvorschauMany Rails developers today have never worked with the Java EE packaging process and launch their applications by navigating to the top level of their Rails project and starting one of two popular Ruby web servers: Mongrel or WEBrick. You want to run the Jetty application server with your Rails application but use a deployment method more familiar to Rails developers.Use the
jetty_railsgem, which allows you to run a Rails application with the Jetty server without performing any Java EE packaging. First, install thejetty_railsgem:jruby –S gem install jetty_rails
Then, go to the top of your Rails application and start the Jetty server:$ cd jrubycook_application $ jruby -S jetty_rails
You can get a list of some common startup parameters by running this command:jruby –S jetty_rails --help
Theportandenvironmentoptions are common startup parameters used in the Mongrel and WEBrick HTTP servers:- Pass in the
--port <port>or–p <port>parameter to set the port of your web . The default is 3000. - Use the
--environment <env>or–e <env>to specify the Rails execution environment. The default value isdevelopment. - Set the
--context-path <path>or–u <path>parameter to change your applications context root. Remember to make your Rails application aware of this change of code to your environment.rb file:ActionController::AbstractRequest.relative_url_root = "/my_new_context_root"
- Use the
–cor--configparameter to load the server configuration through an external file. The server will look in the default location, config/jetty_rails.yml, if you do not include a file path.
The configuration file is valuable beyond the organizational benefit of getting the startup parameters out of the input arguments. As of version 0.6, you can use the file to tune your application by setting JRuby and Jetty configuration values, leverage a layered configuration system, and run multiple Rails applications within a single Jetty instance.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Deploying Rails with Mongrel
- InhaltsvorschauYou want to run a JRuby on Rails application with Mongrel.Install the Mongrel gem. The JRuby gem installer should select the latest Java version of the gem:
$ jruby –S gem install mongrel –-no-ri –-no-rdoc Updating metadata for 165 gems from http://gems.rubyforge.org ...................................................................... complete Successfully installed gem_plugin-0.2.3 Successfully installed mongrel-1.1.4-java 2 gems installedInclude the JDBC adapter of your database in your classpath if you aren’t using the database-specificjdbcadapter that packages and loads the driver. Go to your Rails application’s home directory and start Mongrel:$ jruby –S mongrel_rails start ** Starting Mongrel listening at 0.0.0.0:3000 ** Starting Rails with development environment... ** Rails loaded. ** Loading any Rails specific GemPlugins ** Signals ready. TERM => stop. USR2 => restart. INT => stop (no restart). ** Rails signals registered. HUP => reload (without restart). It might not wor k well. ** Mongrel 1.1.4 available at 0.0.0.0:3000 ** Use CTRL-C to stop.Mongrel is a small but high-performance web server originally written in Ruby and C. Recently, the C portions have been ported to Java so that Mongrel can run under JRuby. This was an important milestone for the project given that many Rails developers use Mongrel in their production and development environments.There is an experimental gem to provide clustering support for the Java version of Mongrel calledmongrel_jcluster. Unfortunately, this gem is currently only supported on Linux, OS X, and Cygwin on Windows. The default Windows DOS shell is currently not yet supported. This gem allows you easily start and stop sets of Mongrel servers and attempts to recreate some of the functionality ofmongrel_cluster, which is incompatible with JRuby. First, install the gem:$ jruby –S gem install mongrel_jcluster Successfully installed mongrel_jcluster-0.0.1 1 gem installedNext, generate a configuration file for your Mongrel cluster:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Deploying Rails on the GlassFish v2 Server
- InhaltsvorschauYou want to deploy a Rails application on the GlassFish v2 application server.Install the GlassFish server and navigate to the home directory. Set up the deployment area and configure the server with the supplied
anttask:$ $GLASSFISH_HOME/lib/ant/bin/ant -f setup.xml
This will install several libraries and create your Java EE application deployment folder at $GLASSFISH_HOME\domains\domain1\autodeploy. Package your Rails application as a Java EE WAR (see ). If you’ve defined a JDBC connection with thejdbcadapter or using a JNDI DataSource, remember to include the JDBC adapter in your classpath or copy the JAR file into $GLASSFISH_HOME/lib to make it available to your web applications.Start the server with this command:$ $GLASSFISH_HOME/bin/asadmin start-domain
Wait a few seconds after the server starts to allow enough time to deploy your Rails WAR ().
Figure : Starting up the GlassFish serverOpen your browser to http://localhost:8080/MyKillerApplication to view your Rails project.Rails applications that use a JNDI DataSource can use theasadmincommand with input parameters to define the DataSource’s properties. This example creates a connection pool for a MySQL server at our standard example addressjdbc/rails_db:$ $GLASSFISH_HOME\bin\asadmin create-jdbc-connection-pool –datasourceclassname \ com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource \ --restype javax.sql.DataSource –property User=root:Password=password:\ URL=jdbc\:mysql\://localhost:3316/jrubycookbook_development jdbc/rails_db Command create-jdbc-connection-pool executed successfully.
Next, make the new DataSource available to your Rails WAR and other Java EE installed on the server:$ $GLASSFISH_HOME\bin\asadmin create-jdbc-resource --connectionpoolid \ jdbc/rails_db jdbc/rails_db Command create-jdbc-resource executed successfully.
- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using the GlassFish v3 Gem
- InhaltsvorschauYou want to run a Rails application with the GlassFish v3 gem.First, install the GlassFish v3 gem:
$ jruby –S gem install glassfish Successfully installed glassfish-0.1.2-universal-java 1 gem installedStart your Rails application with the newglassfish_railscommand. You currently have to start the server in the directory that contains your Rails application directory:$ jruby -S glassfish_rails MyKillerApplication
Open your browser to http://localhost:3000 and you should see the Rails welcome screen.The GlassFish v3 server is Sun’s latest effort to build a widely adopted Java EE server. They have packaged this server as a Ruby gem and configured it to run Rails with a few simple commands.The gem implements a pool of JRuby runtimes that work a lot like the pooling used in the GoldSpike servlet. You can set the number of JRuby runtimes in the pool by using the–nor the--runtimesflag when starting the server. The following examples will start up servers with three runtimes in each pool:$ jruby –S glassfish_rails MyKillerApplication –n 3
or:$ jruby –S glassfish_rails MyKillerApplication –-runtimes 3
- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using ActiveRecord Outside of Rails
- InhaltsvorschauYou want to use ActiveRecord as the Object-Relational Mapping (ORM) solution for a non-Rails application.If you have not installed Rails, install the
activerecordgem:$ jruby -S gem install activerecord --no-ri --no-rdoc
Install theactiverecord-jdbc-adaptergem, which will provide access to the database through a JDBC connection:$ jruby -S gem install activerecord-jdbc-adapter --no-ri --no-rdoc
Include your database’s JDBC adapter in your classpath or JRuby lib folder if you’re not using a database-specific adapter. For example, to connect to a MySQL database, you will need theactiverecord-jdbcmysql-adaptergem. See for more about database-specific drivers and gems.$ jruby -S gem install activerecord-jdbcmysql-adapter --no-ri --no-rdoc
Create a YAML file called database.yml such as the one in to define your database connection parameters.Example . Sample database.yml filedevelopment: adapter: jdbcmysql database: jrubycookbook_development host: localhost port: 3306 username: root password: password
Once this setup is in place, you can load the file and establish a connection to one of the databases defined in it. In , we load thedevelopmentdatabase defined in the configuration file from . Once the database connection has been established, we run a query and iterate through the results. Finally, we utilize one of the dynamic finder methods that are attached to objects by the ActiveRecord .Example . Loading a database.yml file and accessing the databaserequire 'rubygems' gem 'activerecord-jdbcmysql-adapter' require 'active_record' require 'yaml' @connections = YAML.load_file("database.yml") ActiveRecord::Base.establish_connection(@connections["development"]) stmt = "select id, title from games" @val = ActiveRecord::Base.connection.select_all(stmt) @val.each do |g| puts "game id: #{g["id"]} #{g["title"]}" end class Game < ActiveRecord::Base end puts "found game id: #{Game.find(1).id}"This is the output of the program:$ jruby games.rb game id: 1 Alien Invasion looking up game id: 1Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Accessing Common Java Servlet Information
- InhaltsvorschauYou want to access the Java servlet request object from your Rails controllers.JRuby-Rack’s servlet filter makes several servlet variables available to the Rails application on each incoming request. Access the standard
javax.servlet.ServletRequestthrough the Rack environment map with the keyjava.servlet_request. TheServletContextobject can also be fetched through the Rack environment hash with thejava.servlet_contextkey, or through the global variable,$servlet_context. shows a controller that uses some of these variables.Example . Accessing the Java servlet objects from a Rails controllerclass HelloWorldController < ApplicationController def hello ctx = request.env['java.servlet_context'] puts "server info: #{ctx.server_info}" puts "server info: #{$servlet_context.server_info}" req = request.env['java.servlet_request'] puts "uri: #{req.request_uri}" puts "query string: #{req.query_string}" puts "port: #{req.server_port}" puts "param hello: #{req.get_parameter("hello")}" puts "session id: #{req.get_session.id}" end endAccessing http://localhost:3000/MyKillerApplication/hello?hello=world would output these messages to the container’s log file:server info: jetty-6.1.9 server info: jetty-6.1.9 uri: /hello_world/hello query string: hello=world port: 3000 param hello: world session id: 2026
JRuby-Rack does not provide access to theServletResponseobject from within your controller. This feature was available in earlier versions of Warbler through the GoldSpike servlet but has been removed after the integration of JRuby-Rack.- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Configuring Session Storage
- InhaltsvorschauYou want to configure the session storage mechanism used by your Rails application.Edit the web.xml file in your web application and set the
jruby.session_storecontext parameter todbby adding this bit of code:<context-param> <param-name>jruby.session_store</param-name> <param-value>db</param-value> <!-- This value really means let Rails take care of session store --> </context-param>By default, JRuby-Rack’s servlet filter uses the Java EE servlet container’s session storage. Changing thejruby.session_storecontext parameter todbtells JRuby-Rack to defer to Rails’s session management.- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Controlling the Classes, Directories, and Other Files Packaged into a Rails WAR File
- InhaltsvorschauThere are classes and other files you want to include and/or exclude from your WAR file.Open the Warbler configuration file config/warbler.rb and validate these configuration options:
# Application directories to be included in the webapp. config.dirs = %w(app config lib log vendor tmp) # Additional files/directories to include, above those in config.dirs config.includes = FileList["db"] # Additional files/directories to exclude config.excludes = FileList["lib/tasks/*"] # Additional Java .jar files to include. Note that if .jar files are placed # in lib (and not otherwise excluded) then they need not be mentioned here # JRuby and JRuby-Rack are pre-loaded in this list. # Be sure to include your own versions if you directly set the value config.java_libs += FileList["lib/java/*.jar"] # Loose Java classes and miscellaneous files to be placed in WEB-INF/classes. config.java_classes = FileList["target/classes/**.*"] # One or more pathmaps defining how the java classes should be copied into # WEB-INF/classes. The example pathmap below accompanies the java_classes # configuration above. See http://rake.rubyforge.org/classes/String.html#M000017 # for details of how to specify a pathmap. config.pathmaps.java_classes << "%{target/classes/,}"By default, Warbler will include the JRuby runtime and JRuby-Rack in the WAR files it produces. There are some cases where you might prefer to install these JARs in a shared library area rather than packaging the JAR files with each web application. The shared packaging approach can accomplish this, but some developers may want a mixed approach, in which the packaged WAR file includes dependent gems but not the JRuby runtime and the JRuby-Rack servlet. Theconfig.java_libsproperty is simply a Ruby array, so you can use well-known array operations to exclude items from Warbler’s build process. For example, you can use thereject!method with a regular expression to exclude all versions of JRuby and JRuby-Rack from the final WAR file:config.java_libs.reject! {|lib| lib =~ /jruby-complete|jruby-rack/ }Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Changing the Name of the WAR File and the Staging Area
- InhaltsvorschauYou want to change the name of the WAR file and/or Warbler’s staging area.By default, Warbler will name the generated WAR file according to the Rails application’s directory name. You can customize the name by setting the
config.war_nameparameter in your config/warbler.rb configuration file:# Name of the war file (without the .war) -- defaults to the basename # of RAILS_ROOT config.war_name = "mywar"
You may also want to modify the staging folder that contains the decompressed source files for the final WAR. In warbler.rb, set theconfig.staging_dirto your target staging folder:# Temporary directory where the application is staged config.staging_dir = "tmp/war"
- ”
- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Deploying a Rails Application to the Root Context
- InhaltsvorschauYou want to make your Java EE web application available from the root context of the servlet container.In general, the simplest approach is to package your Rails application with the name ROOT.war. This can be configured using the Warbler configuration file, warble.rb:
config.war_name = "ROOT"
Before deploying this WAR file, be sure to remove any existing directories named ROOT or ROOT.war files from your container’s deployment directories.Although not actually part of the Java EE standard, using a filename of ROOT.war to indicate to the servlet container that you want this application to be deployed in the root context is a widely used convention. Each container defines a custom deployment descriptor. We’ve seen examples of these descriptors in previous recipes. If you are using JNDI DataSources, you will need to modify the deployment descriptors to match the context name.Tomcat
Edit the context.xml file in the META-INF directory in your staging area (see ). Set thepathanddocBaseattributes to/(). Warbler does not create this file by default so you will have to create it yourself and repackage the WAR.Example . Changing the context path for a Tomcat deployment<Context path="/" docBase="/" debug="5" reloadable="true" crossContext="true"> <Resource name="jdbc/rails_db" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="root" password="password" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/jrubycookbook_development?autoReconnect=true"/> </Context>JBoss
Edit the jboss-web.xml file in the WEB-INF directory in your staging area (see ). Change thecontext-rootvalue to/(). Warbler does not create this file by default so you will have to create it yourself and repackage the WAR.Example . Changing the context path for a JBoss deployment<jboss-web> <context-root>/</context-root> <resource-ref> <res-ref-name>jdbc/rails_db</res-ref-name> <res-type>javax.sql.DataSource</res-type> <jndi-name>java:rails_db</jndi-name> </resource-ref> </jboss-web>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating a Rails Application with Aptana Studio
- InhaltsvorschauYou want to create a Rails application using Aptana Studio.Download and install the Aptana Studio software from the Aptana website, http://www.aptana.com/download. Open the Aptana start page at Help→Aptana Studio Start Page and scroll to the RadRails information in the Plugins column. Click on the Install button on the start page and complete the installation wizard. You can also install the plugin by selecting the RadRails item in the Plugin Manager, located in a tab in the bottom frame, and clicking on the installation icon. Both options are shown in .
Figure : Aptana Studio: RadRails installation optionsAptana is built on the Eclipse IDE platform. As a result, the solution from should be followed to set up the JRuby runtime and other common Eclipse configuration options. Once configuration is complete, choose the RadRails perspective by clicking on the new RadRails icon or select Other→RadRails in the perspectives menu in the top right corner of the window. Create your new Rails application by selecting File→New→Rails Project in the menu. Give the project a name and choose your database platform from the available options. Click Finish, and RadRails will generate the files for your Rails application, which are shown in the left Rails File window. The default wizard settings will also create and start a Mongrel server instance. The editor should be displaying the Aptana welcome screen shown in . Open the Rails database configuration file at config/database.yml in the left Explorer window and edit the values for your database. You can start and stop your Mongrel server by navigating to the Servers tab found in the bottom center window. Select your Rails application in the list and use the controls to start the server in regular or debug mode.
Figure : RadRails Interface and Welcome screenThe Rails Shell was introduced with RadRails version 1.0 and gives the developer access to Rails commands through a command-line interface. Choose the Console tab in the bottom panel or choose Open a Rails Shell in the console options. The shell and the location of the options button are shown in . The Rails Shell complements the graphical interfaces for performing common Rails tasks and brings the IDE more in line with the Rails developers’ preference of administering their application through a shell interface. The Rails Shell allows you to execute generator scripts, Rake tasks, and migrations, and create Rails projects and install gems and plugins.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Accessing Static Files in Your Rails Java EE Application
- InhaltsvorschauWarbler packages your Rails application by separating the static content from the executable code and moving it into the top-level directory in the WAR. This creates problems for some Rails functions such as
render :filebecause the file paths it is generating are now incorrect. You would like your Rails application to serve static content in both a standard deployment and when assembled using Warbler.Add a hook into your Rails application by creating a public_dir.rb file in the initializers directory. Evaluate the$servlet_contextvariable, which is only set when running in a Java EE environment, and set the location of the public directory based on the existence of the variable. shows a technique for toggling the public directory.Example . Public directory detection codePUBLIC_DIR = if defined?($servlet_context) $servlet_context.getRealPath('/') else "#{RAILS_ROOT}" + '/public' endReplace all the calls in your Rails code fromrender :file => "/public/data/jobs.log"torender :file => "#{PUBLIC_DIR}/data/jobs.log".You will also need to patch Rails’ internal functions that build paths to static files. Therender_optional_error_fileinActionControllercan be patched by adding the code in to your Rails application.rb file. A new module with patched method is mixed into the originalActionControllermodule at runtime.Example . Patching functions that serve static filesmodule Cookbook module PublicRescueExtensions protected def render_optional_error_file(status_code) status = interpret_status(status_code) path = "#{PUBLIC_DIR}/#{status[0,3]}.html" if File.exists?(path) render :file => path, :status => status else head status end end end end ActionController::Rescue.send :include, Cookbook::PublicRescueExtensions- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 3: Java Integration
- InhaltsvorschauThe first two chapters examined JRuby almost entirely from a Ruby-centric perspective. In the next few chapters, we look at leveraging JRuby more as a toolkit for Ruby and Java integration. There are two primary integration approaches that we will explore in this chapter. The first is how JRuby can be used to add functionality to a Java application; the second is how Ruby programs can take advantage of the wide array of Java libraries. Frequently, these types of integration are combined. For , when mixing Java and Ruby code, using a consistent configuration for logging can be useful, something which is explored in .There are three primary APIs for embedding Ruby into a Java application:
- The JRuby low-level API
- The Bean Scripting Framework (BSF)
- Java Scripting, defined by JSR 223
These APIs are the subject of the first three recipes in this chapter. The differences between the low-level API and either BSF or Java Scripting are fairly obvious—the low-level API ties your Java code directly to JRuby, whereas both BSF and Java Scripting are abstractions of the JRuby runtime and, in fact, support multiple scripting languages. In general, you will use the JRuby API when you need tight control over the runtime’s configuration. The choice between BSF and Java Scripting is largely based on deployment environment—BSF support is more consistent on Java 5, whereas Java Scripting is only available as a backport.Regardless of the mechanics, the value of using JRuby in this way primarily stems from the fact that Ruby code is interpreted, not compiled. This allows you to store Ruby code in a JavaStringobject and evaluate it while your application is running. For , a reporting application could store the Ruby code necessary to generate a report in a database. Another scenario would be to have an application through Ruby-based plugins that could be added or removed while the is running, something not typically associated with Java applications. A technique has been used extensively in gaming, most notably the popular, massive multiplayer game World of Warcraft, which can be extended by users using the Lua scripting language (even though the core is written in C++).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Introduction
- InhaltsvorschauThe first two chapters examined JRuby almost entirely from a Ruby-centric perspective. In the next few chapters, we look at leveraging JRuby more as a toolkit for Ruby and Java integration. There are two primary integration approaches that we will explore in this chapter. The first is how JRuby can be used to add functionality to a Java application; the second is how Ruby programs can take advantage of the wide array of Java libraries. Frequently, these types of integration are combined. For , when mixing Java and Ruby code, using a consistent configuration for logging can be useful, something which is explored in .There are three primary APIs for embedding Ruby into a Java application:
- The JRuby low-level API
- The Bean Scripting Framework (BSF)
- Java Scripting, defined by JSR 223
These APIs are the subject of the first three recipes in this chapter. The differences between the low-level API and either BSF or Java Scripting are fairly obvious—the low-level API ties your Java code directly to JRuby, whereas both BSF and Java Scripting are abstractions of the JRuby runtime and, in fact, support multiple scripting languages. In general, you will use the JRuby API when you need tight control over the runtime’s configuration. The choice between BSF and Java Scripting is largely based on deployment environment—BSF support is more consistent on Java 5, whereas Java Scripting is only available as a backport.Regardless of the mechanics, the value of using JRuby in this way primarily stems from the fact that Ruby code is interpreted, not compiled. This allows you to store Ruby code in a JavaStringobject and evaluate it while your application is running. For , a reporting application could store the Ruby code necessary to generate a report in a database. Another scenario would be to have an application through Ruby-based plugins that could be added or removed while the is running, something not typically associated with Java applications. A technique has been used extensively in gaming, most notably the popular, massive multiplayer game World of Warcraft, which can be extended by users using the Lua scripting language (even though the core is written in C++).Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Executing Ruby from Java
- InhaltsvorschauYou want to execute some Ruby code from a Java application.Obtain an instance of
org.jruby.Rubyand call theevalScriptlet()method. Theorg.jruby.javasupport.JavaEmbedUtilsclass provides static factory methods for creating an instance of the JRuby runtime. shows a simple usage of these classes.Example . Calling Ruby from Javapackage org.jrubycookbook.ch03; import java.util.Collections; import org.jruby.Ruby; import org.jruby.javasupport.JavaEmbedUtils; public class RubyRunner { public static void main(String[] args) { // Create an instance of the JRuby runtime. The parameter to initalize() // is a list of paths to be added to the Ruby load path. Ruby runtime = JavaEmbedUtils.initialize(Collections.EMPTY_LIST); runtime.evalScriptlet("puts 'hello world'"); } }When run, this class outputs the classic greeting:hello world
Prior to JRuby 1.0.3, the method used to obtain instances of the JRuby runtime wasRuby.getDefaultInstance(). Although this usage has been deprecated, you may see it from time to time in code examples.Every execution ofJavaEmbedUtils.initialize()will create a new instance of the JRuby runtime. JRuby also provides a mechanism for reuse of JRuby runtimes within a single Java thread. To enable this, set the Java system propertyjruby.runtime.threadlocalto"true". If this is set, calls toJavaEmbedUtils.initialize()will create a new instance and store that instance in aThreadLocalvariable. To access this instance, callRuby.getCurrentInstance(). illustrates instance reuse by setting and retrieving a global variable within the runtime.Example . Using the current JRuby runtimepackage org.jrubycookbook.ch03; import java.util.Collections; import org.jruby.Ruby; import org.jruby.javasupport.JavaEmbedUtils; public class RubyRunner2 { public static void main(String[] args) { // Enable ThreadLocal support System.setProperty("jruby.runtime.threadlocal", "true"); // Create a JRuby instance Ruby runtime = JavaEmbedUtils.initialize(Collections.EMPTY_LIST); // Execute a bit of Ruby code that creates a variable runtime.evalScriptlet("$message = 'hello world from JRuby'"); runtime.evalScriptlet("$counter = 0"); for (int i = 0; i < 5; i++) { outputMessage(); } } private static void outputMessage() { Ruby runtime = Ruby.getCurrentInstance(); String scriptlet = "puts \"<#{$counter}> #{$message}\""; runtime.evalScriptlet("$counter = $counter.next"); runtime.evalScriptlet(scriptlet); } }Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Invoking JRuby Through the Bean Scripting Framework
- InhaltsvorschauYou want to execute some Ruby code from a Java application and want the flexibility to support multiple scripting language implementations.Use the Bean Scripting Framework (BSF):
- Add bsf.jar, included with JRuby distributions, to your Java classpath.
- Register the JRuby scripting engine with the BSF runtime.
- Create an instance of the
org.apache.bsf.BSFManagerclass. - Call the
eval()orexec()method on theBSFManagerobject.
shows a simple usage of JRuby through BSF.Example . Invoking JRuby with BSFpackage org.jrubycookbook.ch03; import org.apache.bsf.BSFException; import org.apache.bsf.BSFManager; public class RubyBSFRunner { public static void main(String[] args) throws BSFException { BSFManager.registerScriptingEngine("ruby", "org.jruby.javasupport.bsf.JRubyEngine", new String[] { "rb" }); BSFManager manager = new BSFManager(); manager.exec("ruby", "<script>", 1, 1, "puts 'hello world'"); } }The Bean Scripting Framework is an open source software framework originally by IBM that is now part of the Apache Jakarta project. It provides a generic application programming interface (API) for supporting scripting languages within Java applications. BSF comes with built-in support for several scripting languages, :- JavaScript
- NetRexx
- Python
- Tcl
- XSLT
In addition to these languages, the Bean Scripting Framework defines a service provider interface (SPI) that allows other scripting languages to be plugged in by implementing theorg.apache.bsf.BSFEngineinterface. JRuby provides an implementation of this interface with the classorg.jruby.javasupport.bsf.JRubyEngine. As you can see in , it is necessary to register this class with BSF by callingBSFManager.registerScriptingEngine(). When registering this engine implementation (or any other), you have to provide BSF with both the name of the scripting language (ruby) and a list of possible file extensions (rb). BSFManager provides two methods for invoking a scripting language:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Invoking JRuby Through Java Scripting Support
- InhaltsvorschauYou are running Java 6 (or later), and you want to execute some Ruby code from a Java application and want the flexibility to support multiple scripting language .Use Java’s built-in scripting framework, defined in JSR (Java Specification Request) 223:
- Download jsr223-engines.zip from https://scripting.dev.java.net.
- Unzip the file jruby/build/jruby-engine.jar from jsr223-engines.zip and add it to your classpath.
- Create an instance of
javax.script.ScriptEngineManager. - Call
getEngineByName("ruby")to obtain an instance ofjavax.script.ScriptEngine. - Call the
eval()method on theScriptEngineobject.
shows a simple usage of JRuby using the JSR 223 API.Example . Invoking JRuby through javax.script.ScriptEngineManagerpackage org.jrubycookbook.ch03; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; public class Ruby223Runner { public static void main(String[] args) throws ScriptException { ScriptEngineManager scriptManager = new ScriptEngineManager(); ScriptEngine engine = scriptManager.getEngineByName("ruby"); engine.eval("puts 'hello world'"); } }JSR 223: Scripting for the Java Platform was one of the more highly anticipated upgrades to the Java platform in the Java 6 release. At the simplest level, it provides a standardized version of the API (and SPI) that the Bean Scripting Framework (BSF) had provided for many years. Almost more importantly, however, is the message that JSR 223 sends to the programming community as a whole by formalizing the distinction between Java the language and Java the platform. JSR 223’s mere existence suggests that the Java platform will provide a suitable runtime environment for a variety of scripting languages, including Ruby/JRuby.As you can see by comparing with , the JSR 223 API is simpler to use than the BSF API in that proactive registration of scripting engines is not required. JSR 223 defines a discovery mechanism that allows script engines to be automatically discovered based on the existence of a file in theEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Logging from Ruby with Jakarta Commons Logging
- InhaltsvorschauYou are running Ruby code within a Java application that uses Jakarta Commons Logging (JCL) and wish your log messages to be consistent.Use a class like the one in to transform fully qualified Ruby class names into identifiers that resemble fully qualified Java class names.Example . Custom JRuby LogFactory bridge class
package org.jrubycookbook.ch03; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jruby.RubyObject; public class JRubyLogFactory { public static Log getLog(RubyObject o) { String rubyClassName = o.getMetaClass().getName(); String logName = rubyClassName.replace("::", "."); return LogFactory.getLog(logName); } }Once this is in place, you can reference this class in your Ruby code and create newLogobjects by passingselfto thegetLog()method. Log messages will be logged under a log name derived from the fully qualified Ruby class name. The script in will log a message under the log nameLog.LogTest.Example . Using the JRubyLogFactory bridge classinclude Java import org.jrubycookbook.ch03.JRubyLogFactory module Log class LogTest def initialize @log = JRubyLogFactory.getLog(self) end def hello @log.info("hello via jcl") end end end Log::LogTest.new.helloJakarta Commons Logging is a popular Java library for providing a consistent logging API across several logging implementations, including Log4J, thejava.util.loggingpackage, LogKit, and JCL’s own SimpleLog. JCL is especially popular amongst library developers as it allows the library to work with several logging implementations without having a compile-time dependency to any of them. Java code will typically obtain an implementation of theorg.apache.commons.logging.Loginterface by calling one of two factory methods:LogFactory.getLog(Class)LogFactory.getLog(String)
The former calls the latter passing the fully qualified class name. As many logging packages allow you to configure logging using a hierarchal model, i.e., all logs whose names begin withEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using the Java Concurrency Utilities
- InhaltsvorschauYou want to use the classes in the
java.util.concurrentpackage to write code that is both thread-safe and highly performant.Simply reference the classes in your Ruby code. For example, to create an instance ofjava.util.concurrent.ConcurrentHashMap, just use the constructor:$hash = java.util.concurrent.ConcurrentHashMap.new
Likewise, thejava.util.concurrent.Executorsfactory class can be used to create powerful yet easy-to-use thread pools. In , a thread pool containing two threads is created and used from Ruby code.Example . Using a java.util.concurrent thread pool from Rubyinclude Java class MyLongTask include java.util.concurrent.Callable def initialize(label) @label = label end def call puts "about to sleep in task labeled #{@label}\n" # artificially create a longer delay sleep 5 puts "done sleeping in task labeled #{@label}\n" return "result of the long task labeled #{@label}\n" end end # create a new thread pool executor = java.util.concurrent.Executors::newFixedThreadPool(2) # create an array to store the future value references future = Array.new puts "submitting first task" future[0] = executor.submit(MyLongTask.new("first")) puts "submitting second task" future[1] = executor.submit(MyLongTask.new("second")) puts "submitting third task" future[2] = executor.submit(MyLongTask.new("third")) puts "All tasks have been submitted" # this method call will block until the first task has completed puts future[0].get() # this method call will block until the second task has completed puts future[1].get() # this method call will block until the third task has completed puts future[2].get()The exact output of this code may vary slightly from execution to execution, but in general you will see all three tasks being submitted, followed by the first two tasks starting to sleep. Eventually, those tasks will complete and the third will start. However, since there are multiple threads, the first two tasks may be completed in any order, as seen here:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating JavaBean Style Accessor Methods
- InhaltsvorschauRuby developers use the
attr_accessorfunction as a convenient way to declare instance variables and createreadandwritemethods in a class. You would like a similar function that can add JavaBean-stylegetandsetmethods to a class with a condensed and syntax.Start by creating a Ruby module that will contain the new method. The function can be coded directly into your classes, but the module encourages more reusable and less repetitive code. Create a method calledjava_attr_accessorthat accepts a list of symbols, consistent with Ruby’sattr_accessormethod. The symbols are named with the Ruby style of using underscores as word delimiters, but the function will convert each symbol into the JavaBean-style equivalent name by adding thegetandsetprefixes to the camel case representation of the name. shows the module and a class that adds several instance variables using thejava_attr_accessormethod after extending the new module.Example . Helper module for JavaBean accessorsmodule Helper def java_attr_accessor(*symbols) symbols.each { |symbol| camelcased = symbol.to_s.capitalize.gsub(/\_[a-zA-Z]/) {|s| s[1..1].upcase} module_eval( "def get#{camelcased}() @#{symbol}; end" ) module_eval( "def set#{camelcased}(val) @#{symbol} = val; end" ) } end end class Example extend Helper java_attr_accessor :title,:first_name end mc = Example.new mc.setTitle('Cookbook') mc.setFirstName("John")This utility function can be very useful when working with applications or frameworks that make heavy use of JavaBeans, such as Hibernate and Spring.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Writing Consistent Code
- InhaltsvorschauYou are calling both Ruby and Java libraries from Ruby and want the code to look consistent. This line from is very obviously calling a Java method:
@log = JRubyLogFactory.getLog(self)
Replace camel-cased method names with method names that follow the Ruby naming convention: all lowercase letters and underscores for word separators. The line from referenced above could be rewritten as:@log = JRubyLogFactory.get_log(self)
JRuby provides this automatic method translation as a way of blending Java and Ruby method calls together.JRuby won’t override an existing method. If there was an actual method namedget_log(), it takes precedence. That caveat aside, using this feature leads to a more consistent coding style.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Transforming XML with TrAX
- InhaltsvorschauYou want to transform XML documents using XSLT through Java’s Transformation API for XML (TrAX).Import the class
javax.xml.transform.TransformerFactoryas well as the classes to be used for the input and output, typicallyjavax.xml.transform.stream.StreamSourceandjavax.xml.transform.stream.StreamResult. If you will be transforming with the same stylesheet repeatedly, create ajavax.xml.transform.Templatesobject to save the stylesheet. If this is a one-time transformation, simply create ajavax.xml.transform.Transformerobject. shows both scenarios.Example . Using TrAX from JRubyinclude Java import javax.xml.transform.TransformerFactory import javax.xml.transform.stream.StreamResult import javax.xml.transform.stream.StreamSource # Create a new TransformerFactory instance factory = TransformerFactory.new_instance # Compile a stylesheet into a Template object style_input = StreamSource.new("rss.xslt") templates = factory.new_templates(style_input) # Setup sources for input and output input = StreamSource.new("http://www.mtv.com/rss/news/news_full.jhtml") output = StreamResult.new(java.lang.System.out) # Create a new Transformer from the Template object transformer = templates.new_transformer # Do the transformation transformer.transform(input, output) # Simplified – just create a new Transformer from the stylesheet transformer = factory.new_transformer(style_input) transformer.transform(input, output)TrAX includes a few interfaces that can be easily implemented in Ruby to customize the transformation process. The interfacejavax.xml.transform.ErrorListenerreceives callbacks from theTransformerobject whenever a warning or error is encountered. shows a simple implementation of this interface in Ruby.Example . Implementing javax.xml.transform.ErrorListener in Rubyclass ErrorCounter attr_reader :errors attr_reader :warnings attr_reader :fatals def error(ex) @errors = 0 if (@errors == nil) @errors = @errors + 1 end def warning(ex) @warnings = 0 if (@warnings == nil) @warnings = @warnings + 1 end def fatalError(ex) @fatals = 0 if (@fatals == nil) @fatals = @fatals + 1 end end # Use the ErrorCounter class counter = ErrorCounter.new transformer = factory.new_transformer(style_input) transformer.error_listener = counter transformer.transform(input, output) p "Errors: #{counter.errors}"Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating a Pool of JRuby Runtimes
- InhaltsvorschauYou need to execute Ruby code that is not thread-safe and requires exclusive control of the JRuby runtime and do not want to create new runtimes per thread.Use the Jakarta Commons Pool library to create a pool of JRuby runtimes. When your code needs to invoke JRuby, borrow a runtime from the pool and return it when . To start, download Jakarta Commons Pool from http://jakarta.apache.org/commons/pool/ and add the JAR file to your classpath. Create a subclass of
org.apache.commons.pool.BasePoolableObjectFactorythat creates JRuby runtimes using the methods in . Then use this factory object to construct anorg.apache.commons.pool.impl.GenericObjectPool. shows a subclass ofGenericObjectPoolbuilt for pooling JRuby runtimes.Example . Creating a pool of JRuby runtimespackage org.jrubycookbook.ch03; import java.util.Collections; import java.util.Date; import org.apache.commons.pool.BasePoolableObjectFactory; import org.apache.commons.pool.impl.GenericObjectPool; import org.jruby.Ruby; import org.jruby.javasupport.JavaEmbedUtils; public class JRubyRuntimePool extends GenericObjectPool { private static class JRubyRuntimeFactory extends BasePoolableObjectFactory { public Object makeObject() throws Exception { Ruby runtime = JavaEmbedUtils.initialize(Collections.EMPTY_LIST); return runtime; } } public JRubyRuntimePool() { super(new JRubyRuntimeFactory()); } public Ruby borrowRuntime() throws Exception { return (Ruby) borrowObject(); } public void returnRuntime(Ruby runtime) throws Exception { returnObject(runtime); } public static void main(String[] args) throws Exception { JRubyRuntimePool pool = new JRubyRuntimePool(); // always have a minimum of five runtimes available in the pool. pool.setMinIdle(5); // if there are more than 10 runtimes in the pool, remove the extras pool.setMaxIdle(10); // and don't allow more than 40 runtimes to be in use at the same time pool.setMaxActive(40); // check every minute that the minimum and maximum idle counts are met pool.setTimeBetweenEvictionRunsMillis(60000); // start the application } }Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Performing Remote Management with JMX
- InhaltsvorschauYou want to write a client using Java Management Extensions (JMX) in Ruby to manage a remote Java application.Use the
jmx4rRuby gem. This library significantly simplifies use of the JMX API. To installjmx4r:jruby –S gem install jmx4r
To establish a connection with a JMX service, use theestablish_connectionclass method:JMX::MBean.establish_connection :host => "localhost", :port => 1099
To find an MBean by name, use thefind_by_nameclass method:os = JMX::MBean.find_by_name "java.lang:type=OperatingSystem"
Thefind_by_namemethod returns a dynamic object based around the MBean interface. In the case of the MBean namedjava.lang:type=OperatingSystem, the Java Virtual Machine exposes an MBean with several attributes about the underlying operating system. These JMX attributes can be simply accessed as properties. For example, to output the number of available processors:p "Running with #{os.available_processors} processors."The actual attribute name isAvailableProcessors. The jmx4r library converts this name into a more Ruby-like form.Similarly, JMX operations are invoked as method calls. For example, to force a garbage collection:memory = JMX::MBean.find_by_name "java.lang:type=Memory" memory.gc
The jmx4r library also supports the ability to query for MBeans. shows this functionality in action. In this example, JMX is used to discover the available JMS queues in an Apache ActiveMQ JMS server.Example . Querying MBeansinclude Java require 'rubygems' gem 'jmx4r' require 'jmx4r' JMX::MBean.establish_connection :host => "localhost", :port => 1099 queues = JMX::MBean.find_all_by_name \ "org.apache.activemq:BrokerName=localhost,Type=Queue,*" queues.each do |queue| p "Queue #{queue.name} contains #{queue.queue_size} queued messages." endDepending on the available queues, the output might be similar to this:Queue LogQueue contains 25 queued messages. Queue OrderQueue contains 5 queued messages.
- jmx4r website, http://code.google.com/p/jmx4r/
- Java Management Extensions by J. Steven Perry (O’Reilly)
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Accessing Native Libraries with JRuby
- InhaltsvorschauYou want to access native libraries such as Windows DLLs or Unix shared objects (
.so) from JRuby.Use the Java Native Access (JNA) API to access the operating system’s libraries using only Java or any other JVM-based language like JRuby. JNA uses a dynamic architecture that eliminates the chore of creating, compiling, and distributing native interface files, which was required in other Java frameworks like the Java Native Interface (JNI). shows how you can access the disk information from calls to the native Windows libraries.Example . JNA example showing Windows disk spaceinclude Java import com.sun.jna.ptr.LongByReference Kernel32 = com.sun.jna.NativeLibrary.getInstance('kernel32') GetDiskFreeSpace = Kernel32.getFunction('GetDiskFreeSpaceExA') avail = LongByReference.new total = LongByReference.new total_free = LongByReference.new num = GetDiskFreeSpace.invokeInt(["C:\\", avail, total, total_free].to_java) puts "available: #{avail.value}" puts "total: #{total.value}" puts "total_free #{total_free.value}"JNA is a great match with JRuby and makes it easier to create cross-platform applications that run inside the Java Virtual Machine while still accessing platform-specific APIs. The dynamic architecture is also philosophically in tune with Ruby development because it uses designs that eliminate extraneous code and facilitates rapid .- Java Native Access website, https://jna.dev.java.net
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 4: Enterprise Java
- InhaltsvorschauAs discussed in the introduction to , one of JRuby’s great strengths is its ability to seamlessly interact with the wide variety of available Java libraries. One of the areas where this is most relevant is in the so-called enterprise domain, where Java has become well entrenched. Much of Java’s success has come from the Java Enterprise Edition (Java EE, formerly known as J2EE) platform standards. But platforms that are not Java standards have been just as critical. Two will be covered in this chapter: Spring Framework and Hibernate. Regardless of whether a particular technology is a standard or not, all enterprise Java platforms are designed to enable developers to focus on developing business and presentation logic rather than infrastructure and integration.This chapter starts with a recipe about using Java Naming and Directory Interface (JNDI) objects from Ruby. As its name implies, JNDI is an API for accessing directory services. JNDI presents application developers with a unified interface that can span various services and service types. Within a Java EE application server, JNDI is used by application code to discover resources managed by the server. These could be data sources (a subject discussed throughout ), Enterprise JavaBeans (EJBs), Java Messaging Service (JMS) objects, and a variety of other resources. Your Java EE application server documentation should provide complete details on what resources are available and how you can add additional resources to the server. JNDI can also be used to access external services. In the second and third recipes, we use JNDI to connect to a remote JMS broker using the Apache ActiveMQ server so that we can send and receive JMS messages. In a later recipe, we use JNDI to connect to a Lightweight Access Protocol (LDAP) server and use JRuby to simplify the JNDI API.Following JMS, we will look at implementing an Enterprise JavaBean (EJB). Thanks to the support for annotation-based configuration that arrived with EJB 3, EJB development has become much simpler, yet the lack of annotation support in JRuby means that you still have to write a small amount of bridge code to implement EJBs. Although JRuby and EJB may seem like an odd match at first, the EJB model can provide some significant benefits when being used with JRuby because of the instance pooling provided by Java EE containers. These containers all perform instance pooling for EJBs and only allow one consumer per EJB instance at a time. This means that when writing an EJB, whether using Java or Ruby, you do not need to worry about concurrency: the container does it for you. Many Ruby libraries, most notably ActiveRecord and Rails, have known concurrency problems; using EJBs eliminates the need to create custom instance pools as described in and in the discussion of Rails in .Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Introduction
- InhaltsvorschauAs discussed in the introduction to , one of JRuby’s great strengths is its ability to seamlessly interact with the wide variety of available Java libraries. One of the areas where this is most relevant is in the so-called enterprise domain, where Java has become well entrenched. Much of Java’s success has come from the Java Enterprise Edition (Java EE, formerly known as J2EE) platform standards. But platforms that are not Java standards have been just as critical. Two will be covered in this chapter: Spring Framework and Hibernate. Regardless of whether a particular technology is a standard or not, all enterprise Java platforms are designed to enable developers to focus on developing business and presentation logic rather than infrastructure and integration.This chapter starts with a recipe about using Java Naming and Directory Interface (JNDI) objects from Ruby. As its name implies, JNDI is an API for accessing directory services. JNDI presents application developers with a unified interface that can span various services and service types. Within a Java EE application server, JNDI is used by application code to discover resources managed by the server. These could be data sources (a subject discussed throughout ), Enterprise JavaBeans (EJBs), Java Messaging Service (JMS) objects, and a variety of other resources. Your Java EE application server documentation should provide complete details on what resources are available and how you can add additional resources to the server. JNDI can also be used to access external services. In the second and third recipes, we use JNDI to connect to a remote JMS broker using the Apache ActiveMQ server so that we can send and receive JMS messages. In a later recipe, we use JNDI to connect to a Lightweight Access Protocol (LDAP) server and use JRuby to simplify the JNDI API.Following JMS, we will look at implementing an Enterprise JavaBean (EJB). Thanks to the support for annotation-based configuration that arrived with EJB 3, EJB development has become much simpler, yet the lack of annotation support in JRuby means that you still have to write a small amount of bridge code to implement EJBs. Although JRuby and EJB may seem like an odd match at first, the EJB model can provide some significant benefits when being used with JRuby because of the instance pooling provided by Java EE containers. These containers all perform instance pooling for EJBs and only allow one consumer per EJB instance at a time. This means that when writing an EJB, whether using Java or Ruby, you do not need to worry about concurrency: the container does it for you. Many Ruby libraries, most notably ActiveRecord and Rails, have known concurrency problems; using EJBs eliminates the need to create custom instance pools as described in and in the discussion of Rails in .Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Creating a JNDI Context
- InhaltsvorschauYou need to create a JNDI
Contextobject in order to connect to an LDAP server or JMS broker.Create a Ruby hash with the properties you want to use as the environment and then pass this hash to the constructor ofjavax.naming.InitialContext, wrapping it in ajava.util.Hashtableobject. For example, the code in creates a JNDIContextusing the University of Michigan’s public LDAP server.Example . Creating a custom JNDI Contextinclude Java import java.util.Hashtable import javax.naming.InitialContext import javax.naming.Context env = {Context::INITIAL_CONTEXT_FACTORY => "com.sun.jndi.ldap.LdapCtxFactory", Context::PROVIDER_URL => "ldap://ldap.itd.umich.edu:389" } ctx = InitialContext.new(Hashtable.new(env))Although JRuby will coerce Ruby hashes into Java objects that implement thejava.util.Mapinterface,InitialContextobjects are configured using aHashtable. As a result, the hash must be wrapped by aHashtable.The properties used to instantiate theInitialContextobject can also be stored in a file called jndi.properties in the Java classpath. In the case of , the following would be the contents of jndi.properties:java.naming.factory.initial = com.sun.jndi.ldap.LdapCtxFactory java.naming.provider.url = ldap://ldap.itd.umich.edu:389
With this configuration in place, theInitialContextcan be easily created using the constructor:ctx = InitialContext.new
Regardless of how it is configured, the value of thejava.naming.factory.initialproperty must be a class available on the classpath. As discussed in , JRuby has the ability to add JAR files to the classpath dynamically. However, that capability does not apply to classes used in this type of factory class. This is because JAR files added dynamically to the classpath by JRuby are only visible from Ruby code. Throughout the next recipe, for example, thejava.naming.factory.initialproperty is set toorg.apache.activemq.jndi.ActiveMQInitialContextFactory. If you tried to add this class (and its dependencies) to the classpath in JRuby, aEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Sending JMS Messages
- InhaltsvorschauYour application needs to send messages to a Java Messaging Service (JMS) message broker.Add any necessary JAR files to the classpath. Create a
javax.naming.InitialContextobject as described in . The environment settings will be documented by the JMS broker vendor. For example, to connect to an instance of Apache ActiveMQ, you would use these properties:env = { Context::INITIAL_CONTEXT_FACTORY => "org.apache.activemq.jndi.ActiveMQInitialContextFactory", Context::PROVIDER_URL => "tcp://localhost:61616" }Once theInitialContexthas been properly created, look up the JMSConnectionFactoryandDestinationobjects:connection_factory = ctx.lookup("ConnectionFactory") destination = ctx.lookup("dynamicQueues/output.queue")The rest is simply JMS boilerplate, which we can encapsulate into a Ruby class as seen in .Example . Sending a JMS message from Rubyinclude Java import java.util.Hashtable import javax.naming.InitialContext import javax.naming.Context import javax.jms.Session class JmsSender def initialize(environment) @context = InitialContext.new(Hashtable.new(environment)) @connection_factory = @context.lookup("ConnectionFactory") end def send_text_message(destination_name, message_text) destination = @context.lookup(destination_name) connection = @connection_factory.create_connection() session = connection.create_session(false, Session::AUTO_ACKNOWLEDGE) producer = session.create_producer(destination) message = session.create_text_message message.text = message_text producer.send(message) session.close end end env = { Context::INITIAL_CONTEXT_FACTORY => "org.apache.activemq.jndi.ActiveMQInitialContextFactory", Context::PROVIDER_URL => "tcp://localhost:61616" } sender = JmsSender.new(env) sender.send_text_message("dynamicQueues/output.queue", "hello to JMS from Ruby")This message can then be seen in the ActiveMQ administrative web client, as in .As discussed in , to create ajavax.naming.InitialContextobject usingEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Receiving JMS Messages
- InhaltsvorschauYour application needs to receive messages from a JMS message broker.The initial setup is similar to sending JMS messages: create a JNDI
InitialContextobject and look up theConnectionFactoryand destination from the JNDI context. Using theConnectionFactory, create aConnectionobject and from theConnection, create aSessionobject. TheSessionobject can be used to create aMessageConsumerfor a . TheMessageConsumerobject has two methods for receiving messages, both namedreceive. Ifreceiveis called with no arguments, then the method blocks until a message is available. Ifreceiveis called with an argument (which must be numeric), the method blocks until a message is available or the specific number of milliseconds passes.contains some basic code for receiving a message. Once the message is received, it is inspected to see if it is a text message and, if so, the text is output.Example . Receiving a JMS messageinclude Java import java.util.Hashtable import javax.naming.InitialContext import javax.naming.Context import javax.jms.Session env = { Context::INITIAL_CONTEXT_FACTORY => "org.apache.activemq.jndi.ActiveMQInitialContextFactory", Context::PROVIDER_URL => "tcp://localhost:61616" } context = InitialContext.new(Hashtable.new(env)) connection_factory = context.lookup("ConnectionFactory") destination = context.lookup("dynamicQueues/output.queue") connection = connection_factory.create_connection() session = connection.create_session(false, Session::AUTO_ACKNOWLEDGE) consumer = session.create_consumer(destination) connection.start message = consumer.receive if (message.respond_to? 'text') p "message = #{message.text}" else p "message isn't a text message" end connection.stop session.closeNote that in , we start the connection before receiving a message. A running connection is required before receiving messages whereas it is not for sending messages.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Implementing an Enterprise JavaBean with JRuby
- InhaltsvorschauYou want to encapsulate some Ruby code into an Enterprise JavaBean (EJB) in order to easily integrate it with other EJBs and servlets as well as take advantage of EJB services such as instance pooling, security, and transactions.Create an interface and implementation class for your EJB. A simple EJB interface, annotated with
@Localis in .Example . EJB local interfacepackage org.jrubycookbook.j2ee.ejb; import javax.ejb.Local; @Local public interface Reverser { public String reverse(String string); }In the implementation class, create an initialization method and use it to create an instance of the JRuby runtime. This could be done with any of the techniques discussed in . Annotate this initialization method with the@PostConstructannotation. Then in each business method (i.e., those defined by the EJB interface), wrap the method arguments in Ruby objects, add them to the runtime, and finally execute the appropriate block of Ruby code. includes a JRuby-based EJB class. In this example, the code is inline, but it could just as easily be in an external file.Example . JRuby EJBpackage org.jrubycookbook.j2ee.ejb; import javax.annotation.PostConstruct; import javax.ejb.Stateless; import org.jruby.Ruby; import org.jruby.RubyString; import org.jruby.javasupport.JavaEmbedUtils; @Stateless public class ReverserBean implements Reverser { private Ruby ruby; @PostConstruct public void init() { ruby = JavaEmbedUtils.initialize(Collections.EMPTY_LIST); } public String reverse(String string) { ruby.getGlobalVariables().set("$message", ruby.newString(string)); return ruby.evalScriptlet("$message.reverse").asJavaString(); } }This EJB can then be accessed by servlets and other EJBs in the same container. includes a servlet that uses this EJB.Example . Servlet accessing the JRuby EJBpackage org.jrubycookbook.j2ee.servlet; import java.io.IOException; import javax.ejb.EJB; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.jrubycookbook.j2ee.ejb.Reverser; public class ReverseServlet extends HttpServlet { @EJB private Reverser reverser; protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String result = reverser.reverse(req.getParameter("word")); resp.getWriter().println(result); } }Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Defining Spring Beans in JRuby
- InhaltsvorschauYou use the Spring Framework as a Dependency Injection (DI) container and wish to define some of your beans with JRuby.Create a Java interface that defines the methods you will be implementing in your Ruby class. Use
jrubyelement within thelangnamespace in the Spring XML configuration to define a bean using both the interface and the location of the Ruby script. JRuby beans can also be configured using thelang:propertyelement. A simple JRuby bean definition can be seen in .Example . Simple Spring JRuby bean definition1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:lang="http://www.springframework.org/schema/lang" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/lang 8 http://www.springframework.org/schema/lang/spring-lang.xsd"> 9 10 <lang:jruby id="rubyListener" 11 script-interfaces="org.jrubycookbook.ch04.Listener" 12 script-source="classpath:org/jrubycookbook/ch04/ruby_listener.rb"> 13 <lang:property name="prefix" value="(from Ruby) " /> 14 </lang:jruby> 15 16 </beans>
In this example, lines 2 through 8 are the boilerplate Spring configuration needed to set up both the default andlangnamespaces. Lines 10 through 14 contain the actual bean definition including the setting of a property namedprefix. The interface is defined in and the Ruby implementation is in .Example . Simple interface for Spring beanpackage org.jrubycookbook.ch04; public interface Listener { public void receiveMessage(String message); }Example . Ruby script referenced from Spring configurationclass RubyListener # setter for prefix property def setPrefix(p) @prefix = p end # implementation of Listener interface def receiveMessage(s) puts "#{@prefix}Got Message: #{s}" end end RubyListener.newEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating Refreshable JRuby Spring Beans
- InhaltsvorschauYour Spring container includes beans that you want to reload when their underlying definitions change.Add a
refresh-check-delayattribute to thelang:jrubyelement in your Spring XML configuration file. The use of this attribute tells Spring to watch the resource referenced in thescript-sourceattribute. The value indicates how many milliseconds will pass between scans of the resource for changes.Alternatively, you can apply a default value for the refresh-check-delay attribute by using thedefaultselement in thelangnamespace. For example, to apply a one second delay to all dynamic-language beans in theApplicationContext, include this element in your XML configuration file:<lang:defaults refresh-check-delay="1000"/>
One simple way to demonstrate this refreshable bean functionality is to use Spring’s support for Java Timer objects. The Spring configuration XML in the samerubyListenerbean defined in and adds an implementation ofjava.util.TimerTaskto output the current time. It also includes the Spring plumbing necessary to invoke this task every five seconds.Example . Refreshable JRuby Spring bean called by a TimerTask<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd"> <lang:defaults refresh-check-delay="1000" /> <lang:jruby id="rubyListener" script-interfaces="org.jrubycookbook.ch04.Listener " script-source="classpath:org/jrubycookbook/ch04/ruby_listener.rb"> <lang:property name="prefix" value="(from Timer) " /> </lang:jruby> <bean id="sendDateTask" class="org.jrubycookbook.ch04.SendDateTask"> <property name="listener" ref="rubyListener"/> </bean> <bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask"> <property name="period" value="5000" /> <property name="timerTask" ref="sendDateTask" /> </bean> <bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean"> <property name="scheduledTimerTasks"> <list> <ref bean="scheduledTask" /> </list> </property> </bean> </beans>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Defining JRuby Spring Beans Inline
- InhaltsvorschauYou’re using Spring and want to define beans in JRuby directly inside your Spring XML configuration file instead of in an external file.Instead of providing a resource location with a
script-sourceattribute, you can include JRuby script inside aninline-scriptelement in thelangnamespace as seen in .Example . JRuby script inside an inline-script element<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd"> <lang:jruby id="rubyListener" script-interfaces="org.jrubycookbook.ch04.Listener"> <lang:inline-script><![CDATA[ class RubyListener def setPrefix(p) @prefix = p end # implementation of Listener interface def receiveMessage(s) puts "#{@prefix}Got Message: #{s}" end end RubyListener.new ]]></lang:inline-script> <lang:property name="prefix" value="(from Ruby) " /> </lang:jruby> </beans>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Applying Spring-Aware Interfaces to JRuby Objects
- InhaltsvorschauYour Spring
ApplicationContextcontains JRuby-based beans that need to implement one of theAwareinterfaces, such asorg.springframework.context.ApplicationContextAware.Include implementations of the methods defined in the interface in your JRuby class and add the appropriate interface name to thescript-interfacesattribute.The Spring Framework includes a number of interfaces that can be used to make a bean aware of its surroundings. Generally, these interfaces define a single method that is called by the container during initialization. Here is a sampling of these interfaces:org.springframework.context.ApplicationContextAware- The
ApplicationContextinstance that contains this bean is passed to thesetApplicationContext()method. org.springframework.beans.factory.BeanFactoryAware- The
BeanFactoryinstance that contains this bean is passed to thesetBeanFactory()method. org.springframework.beans.factory.BeanNameAware- The name of this bean in the containing
BeanFactoryis passed to thesetBeanName()method. org.springframework.context.ResourceLoaderAware- A
ResourceLoader, which can resolve aStringidentifier to aResourceobject, is passed to thesetResourceLoader()method. org.springframework.context.MessageSourceAware- A
MessageSource, which can resolve a message code and parameters to an appropriately internationalized message, is passed to thesetMessageSource()method. org.springframework.web.context.ServletContextAware- A
javax.servlet.ServletContextobject is passed to thesetServletContext()method.
shows an inline implementation of theBeanNameAwareinterface.Example . Inline JRuby Spring bean that implements the BeanNameAware interface<lang:jruby id="rubyListener" script-interfaces="org.jrubycookbook.ch04.Listener, org.springframework.beans.factory.BeanNameAware"> <lang:inline-script><![CDATA[ class RubyListener # implementation of BeanNameAware interface def setBeanName(beanName) @beanName = beanName end # implementation of Listener interface def receiveMessage(s) puts "Hello, I'm named #{@beanName}" puts "#{@prefix}Got Message: #{s}" end end RubyListener.new ]]></lang:inline-script> </lang:jruby>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating Spring MVC Controllers with JRuby
- InhaltsvorschauRedeploying a Java controller in Spring MVC can be time-consuming and disruptive to development. This is especially the case for web applications with many modules and/or large amounts of data loaded on startup. You would like to modify your controller code without reloading the running web application.Spring’s dynamic language support can speed up the development of Spring MVC by allowing you to define the controllers as JRuby objects. Not only can you eliminate the compilation step needed for Java development, but with Spring’s bean feature (see ), controller classes can be updated and redefined at runtime without a redeployment of the full web application. Open the Spring configuration file and create a JRuby controller by defining a Spring bean using the dynamic language elements as described in and . Set the value of
script-interfacestoorg.springframework.web.servlet.mvc.Controllerandscript-sourceto the location of a Ruby file that will define and instantiate the controller class. Note that thescripts-sourcevalue is relative to the web application folder. shows a Spring configuration file with a JRuby controller namedhellocontrollerthat renders a JSP page.Example . Spring configuration file with simple JRuby controller<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:lang="http://www.springframework.org/schema/lang" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd"> <lang:jruby id="hellocontroller" refresh-check-delay="3000" script-source="/WEB-INF/ruby/hello.rb" script-interfaces="org.springframework.web.servlet.mvc.Controller"> </lang:jruby> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/hello.htm">hellocontroller</prop> </props> </property> </bean> </beans>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using Hibernate with JRuby
- InhaltsvorschauYou would like to use Hibernate in your JRuby application.Ideally, working with a Hibernate Data Access Object (DAO) should be no different from any other Java class. The main concern for JRuby developers is the use of Java Generics and JRuby’s inability to create classes or call methods with input arguments that use the Generics feature. Hibernate gives Java developers a lot of flexibility in the implementation of the DAO and many leverage Java Generics to reduce the size of classes and method counts. However, the typical pattern for creating DAOs in the most popular online tutorials do not expose the Generics as part of the DAOs’ public API, even though they are used internally. They are commonly created through a factory interface or by instantiating wrapper DAOs for classes. The JRuby program in accesses the
PersonDaothrough a factory while theEventDaois directly .Example . Accessing Hibernate Data Access Objectsinclude Java import example.dao.PersonDao import example.dao.DaoFactory import example.dao.EventDao import example.model.Person import example.model.Event import util.HibernateUtil event_dao = EventDao.new event_dao.set_session HibernateUtil::get_session_factory.get_current_session dao.create(Event.new("JRuby Meeting",java.util.Date.new)) dao.find_all.each do |e| puts "#{e.get_title } #{e.get_date}"; end person_dao = DaoFactory.instantiate(PersonDao.class) dao.create(Person.new("Justin","Wood")) dao.create(Person.new("Brian","Henry")) dao.find_all.each do |p| puts "#{p.get_firstname} #{p.get_lastname}"; endThe Hibernate session is obtained through a static method in theHibernateUtilclass and manually injected into theEventDaoclass. It’s a common Hibernate design pattern to provide access to the Hibernate session factory through a static method in a global utility class. TheHibernateUtilclass becomes the common point of configuration and management and can hide many of the mapping details from your DAOs.Database transactions can be nicely expressed using a Ruby function that yields to an inputted block. The block contains the database interaction code and is evaluated the enclosing parent function’s call to initialize and end the transaction. Errors can be detected and handled in the transaction function and kept out of the business code. The result is clean API that eliminates the verbose and repetitive transaction calls and an enhanced clarity of the transactional code, which is now identified through a function metaphor rather than explicit API calls to begin and end the transaction. defines aEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using the Java Persistence API with JRuby
- InhaltsvorschauYou want to use the Java Persistence API (JPA) in your JRuby application.Use the static JPA method
Persistence.createEntityManagerFactory()to generate a factory for your persistence unit. A call to the factory’screateEntityManager()method generates a newEntityManagerclass, which is your primary tool for accessing the Persistence API. TheEntityManageris analogous to Hibernate’sSessionor Toplink’sClientSessionobject and contains the methods to interact with the database and your model objects. TheEntityManagerobject is not threadsafe and shouldn’t be used with multiple concurrent requests. It is designed to be used and discarded in a relatively short amount of time and not as a long-running software component. shows a JRuby application that creates a fewUserobjects and then queries the database to confirm that they were successfully added.Example . Example JPA access from JRubyinclude Java import javax.persistence.Persistence import cookbook.User def with_trans(em) t = em.getTransaction(); begin t.begin() yield t.commit ensure t.rollback if t.isActive end end emf = Persistence.createEntityManagerFactory("hello-world") em = emf.createEntityManager with_trans(em) do u = User.new("stephen","lee","slee","password","stephen@ora.com") u2 = User.new("stephen","smith","ssmith","password","ssmith@ora.com") em.persist(u) em.persist(u2) end query = em.createQuery("select u from User u where u.firstname = :firstname"). query.set_parameter("firstname", "stephen"). hu = query.get_result_list hu.each do |u| puts "found #{u.firstname} #{u.lastname}" end em.close emf.closeThe example demonstrates the use of a block once again (see ) to express a JPA transaction. This helper method also automatically rolls back the transaction if the commit should fail.- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Making SOAP Calls
- InhaltsvorschauCredit: Steven ShinglerYou need to invoke a remote method through a SOAP-based web service.Use the Mule client module, available from http://mule.mulesource.org, and a Ruby XML parsing library such as REXML or Hpricot. uses Mule to make a request to one of the web services provided by the National Oceanic and Atmospheric Administration (NOAA).Example . Making a SOAP request with the Mule client module
include Java require "rexml/document" import org.mule.module.client.MuleClient url = "axis:http://www.weather.gov/forecasts/xml/SOAP_server/ndfdXMLserver.php" method = "method=LatLonListZipCode" client = MuleClient.new message = client.send("#{url}?#{method}", "10036", nil) doc = REXML::Document.new message.payload puts doc.root.elements[1].text exitTo run this script, Mule and several dependencies need to be added to the classpath. Because of classloader requirements, these dependencies must be on the system classpath (e.g., through the use of theCLASSPATHenvironment variable); they cannot be added to the classpath by using JRuby’s extension of therequiremethod as described in . For this particular script, the dependencies can be added to the classpath using these commands:export MULE_LIB=/opt/mule/lib export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/activation-1.1.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/axis-1.4.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/axis-jaxrpc-1.4.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/backport-util-concurrent-3.1.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-beanutils-1.7.0.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-codec-1.3.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-collections-3.2.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-discovery-0.2.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-httpclient-3.1.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-io-1.3.1.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-lang-2.3.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-logging-1.1.1.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/commons-pool-1.4.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/dom4j-1.6.1.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/geronimo-j2ee-connector_1.5_spec-1.1.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/geronimo-servlet_2.5_spec-1.1.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/jaxen-1.1.1.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/jug-2.0.0-asl.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/mule/mule-core-2.0.2.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/mule/mule-module-client-2.0.2.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/mule/mule-transport-axis-2.0.2.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/saaj-api-1.3.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/stax-api-1.0.1.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/wsdl4j-1.6.1.jar export CLASSPATH=$CLASSPATH:$MULE_LIB/opt/wstx-asl-3.2.6.jar
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Simplifying LDAP Access
- InhaltsvorschauYou are looking up entries and attributes in an LDAP directory through JNDI and are looking to simplify the API.Use JRuby’s open class feature (described in ) to add helper methods to the
com.sun.jndi.ldap.LdapCtxclass.Although powerful, the JNDI API can frequently feel unnecessarily verbose. For example, the Java code required to access a single attribute value is awkward:// Lookup the entry LdapContext entry = ctx.lookup("uid=mts,ou=People,dc=umich,dc=edu"); // First, get all of the Attributes associated with this entry. Attributes attributes = entry.getAttributes(""); // Then get a single named Attribute. Attribute attribute = attributes.get("mail"); // Then actually get the value. String value = (String) attribute.get();For an attribute with multiple values, it’s even worse:// Lookup the entry LdapContext entry = ctx.lookup("uid=mts,ou=People,dc=umich,dc=edu"); // First, get all of the Attributes associated with this entry. Attributes attributes = entry.getAttributes(""); // Then get a single named Attribute. Attribute attribute = attributes.get("mail"); // Then get a NamingEnumeration of the attribute values. NamingEnumeration ne = attribute.getAll(); // Create a list, loop through the NamingEnumeration, // and add each value to the list List<String> values = new ArrayList<String>(); while (ne.hasMore()) { values.add(ne.next()); }shows two methods being added to theLdapCtxclass, which simplify this API significantly.Example . Adding methods to the LdapCtx classinclude Java import com.sun.jndi.ldap.LdapCtx class LdapCtx def get_attribute_value(key) get_attributes("", [key].to_java(:string)).get(key).get end def get_attribute_values(key) values = [] enum = get_attributes("", [key].to_java(:string)).get(key).get_all while enum.has_more values << enum.next end return values end endAdding these methods makes the following code to access the LDAP attributes:entry = ctx.lookup("uid=mts,ou=People,dc=umich,dc=edu") p "Email = #{entry.get_attribute_value("mail")}" entry.get_attribute_values("cn").each do |name| p "Name = #{name}" endEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 5: User Interface and Graphics
- InhaltsvorschauThe JRuby community has paid a lot of attention to web development, but JRuby is also a powerful tool for client application development. By allowing the runtime to access the graphics subsystem, JRuby can be used to create GUI applications with the Abstract Windowing Toolkit (AWT), Swing and the Simple Widget Toolkit (SWT), as well as newer projects like Qt Jambi. These toolkits have a rich set of UI widgets but they also permit tight integration with the native operating system. A few recipes in this chapter explain how to use JRuby to create system tray and desktop components and access native GUI libraries.Given the popularity of declarative programming and Ruby’s powerful Language (DSL) building capabilities, it is to be expected that JRuby developers would explore ways to improve traditional Java UI programming. There are several options to facilitate Swing development: Swigby, Cheri::Swing, Monkeybars, and . Similarly, the Glimmer Eclipse project was created for SWT and QT::JRuby has built-in DSL support.The Rawr gem is a useful tool for packaging your JRuby applications desktop as well as the Web. This gem provides a set of Rake tasks that can be configured to package your JRuby programs as executable JAR files, Windows executables, Mac OS X applications, and Web Start applications. A recipe also describes techniques for using JRuby to build Java applets.Image processing is one of the few areas where Ruby runtimes still depend on native or C code. Use RMagic4J and ImageVoodoo as alternatives to the popular RMagic and ImageScience gems. You can also access the Java 2D API for advanced processing needs.You want to build your Java Swing user interface with JRuby.JRuby’s runtime support extends to the graphics libraries and Swing components. shows a simple Swing application that displays a message in a window.Example . Simple Swing UI
include Java import javax.swing.JFrame frame = JFrame.new "JRuby Message" frame.default_close_operation = JFrame::EXIT_ON_CLOSE msg = javax.swing.JLabel.new "JRuby Rocks" frame.content_pane.add msg frame.pack frame.visible = true
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Introduction
- InhaltsvorschauThe JRuby community has paid a lot of attention to web development, but JRuby is also a powerful tool for client application development. By allowing the runtime to access the graphics subsystem, JRuby can be used to create GUI applications with the Abstract Windowing Toolkit (AWT), Swing and the Simple Widget Toolkit (SWT), as well as newer projects like Qt Jambi. These toolkits have a rich set of UI widgets but they also permit tight integration with the native operating system. A few recipes in this chapter explain how to use JRuby to create system tray and desktop components and access native GUI libraries.Given the popularity of declarative programming and Ruby’s powerful Language (DSL) building capabilities, it is to be expected that JRuby developers would explore ways to improve traditional Java UI programming. There are several options to facilitate Swing development: Swigby, Cheri::Swing, Monkeybars, and . Similarly, the Glimmer Eclipse project was created for SWT and QT::JRuby has built-in DSL support.The Rawr gem is a useful tool for packaging your JRuby applications desktop as well as the Web. This gem provides a set of Rake tasks that can be configured to package your JRuby programs as executable JAR files, Windows executables, Mac OS X applications, and Web Start applications. A recipe also describes techniques for using JRuby to build Java applets.Image processing is one of the few areas where Ruby runtimes still depend on native or C code. Use RMagic4J and ImageVoodoo as alternatives to the popular RMagic and ImageScience gems. You can also access the Java 2D API for advanced processing needs.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Creating Swing Applications
- InhaltsvorschauYou want to build your Java Swing user interface with JRuby.JRuby’s runtime support extends to the graphics libraries and Swing components. shows a simple Swing application that displays a message in a window.Example . Simple Swing UI
include Java import javax.swing.JFrame frame = JFrame.new "JRuby Message" frame.default_close_operation = JFrame::EXIT_ON_CLOSE msg = javax.swing.JLabel.new "JRuby Rocks" frame.content_pane.add msg frame.pack frame.visible = true
JRuby can access the entire Swing API, including advanced features like the Look and Feel libraries. shows how to toggle between Swing’s default Metal theme and the native platform’s Look and Feel.Example . Changing the application’s look and feelinclude Java import javax.swing.JFrame import javax.swing.UIManager frame = JFrame.new "JRuby Look And Feel" frame.default_close_operation = JFrame::EXIT_ON_CLOSE frame.content_pane.layout = java.awt.GridLayout.new(1, 2) {:metal => "javax.swing.plaf.metal.MetalLookAndFeel", :system => UIManager::getSystemLookAndFeelClassName}.each do |l,c| but = javax.swing.JButton.new l.to_s but.add_action_listener do |evt| UIManager::look_and_feel = c javax.swing.SwingUtilities::updateComponentTreeUI frame frame.pack end frame.add(but) end frame.pack frame.visible = trueYou can access third-party Look and Feel libraries such as Substance or Napkin by including their JAR files in the Java classpath and referencing the name of the Look and Feel class.- ”
- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Swing Event Handling
- InhaltsvorschauYou want to handle events that are generated by Swing components.You generally want to use the block coercion feature in JRuby for most GUI event processing. Event listeners that define only a single method such as
javax.awt.event.ActionListenercan make use of this feature and allow for very concise event-handling code. The application in uses blocks to capture the button click event and changes to the text field.Example . Events handled through block coercioninclude Java import javax.swing.JFrame frame = JFrame.new "Event Handler - Coerced" frame.default_close_operation = JFrame::EXIT_ON_CLOSE t = javax.swing.JTextField.new(10) b = javax.swing.JButton.new("search") b.add_action_listener { |evt| puts "searching" }; t.document.add_document_listener { |evt| puts "checking #{t.text}" }; frame.layout = java.awt.GridLayout.new(1, 2) frame.add t frame.add b frame.pack frame.visible = trueYou can also instantiate the listener’s Java interface using theimplmethod, passing a block inside which the event is handled. This approach is useful when the event handler interface contains multiple methods. shows how to intercept events from the menu component.Example . Events handled through an instance of a Java interfaceinclude Java import javax.swing.JFrame frame = JFrame.new frame.default_close_operation = JFrame::EXIT_ON_CLOSE bar = javax.swing.JMenuBar.new menu = javax.swing.JMenu.new "File" item = javax.swing.JMenuItem.new "Open" menu.add_menu_listener(javax.swing.event.MenuListener.impl do |method, evt| puts evt.class case method.to_s when "menuDeselected" puts 'hidden' when "menuSelected" puts 'visible' end end) menu.add item bar.add menu frame.jmenu_bar = bar frame.pack frame.visible = true- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Long-Running Tasks in Swing Applications
- InhaltsvorschauThe Swing event dispatching thread is responsible for drawing the user interface and event handling. You want to execute a long-running task that is initiated from a Swing event but allow the interface to remain responsive and active.The class
javax.swing.SwingWorkeris designed to run long-running jobs while allowing for safe UI updates within the event dispatch thread. The implementation has evolved over the years through several open source projects and publications and was formally added to the core Java library in Java 6. To useSwingWorker, you first create a new class that extendsSwingWorker. Next, implement the requireddoInBackgroundmethod with your long-running action. showsSwingWorkerin action. Note that the button component is a member of the worker class because the variable is not accessible within the scope of the new class.Example . Using the SwingWorker for long-running jobsinclude Java import javax.swing.JFrame frame = JFrame.new "Swing Worker" frame.default_close_operation = JFrame::EXIT_ON_CLOSE start = javax.swing.JButton.new("start") #define the function using a block start.add_action_listener do |evt| class MySwingWorker < javax.swing.SwingWorker attr_accessor :button def doInBackground 10.times do puts "thread #{self.hashCode} working" sleep(1) end self.button.text = "Completed" end end sw = MySwingWorker.new sw.button = start sw.execute end frame.add start frame.pack frame.visible = trueAs of version 1.1, JRuby cannot instantiate abstract Java classes, so you must subclassSwingWorkerto provide the implementation of the abstract methods. This is one of the few areas were JRuby results in less fluid and elegant code than its Java counterpart, but the JRuby team is working on improving support for abstract classes in future versions of JRuby.SwingWorkerhas optional methods that provide advanced features, such as incremental job progress, job cancellation, and completion detection. Explore the API and overload the optional methods in your Ruby class to use these features.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Packaging Standalone Applications
- InhaltsvorschauYou want to package your JRuby application as an executable JAR file, Windows , or Mac OS X application.Install the Rawr gem. This gem was created by David Koontz to simplify the packaging of JRuby applications for Windows, Mac, Linux, and Java environments:
$ jruby –S gem install rawr
Set up the Rawr build environment by running therawr installcommand in your build folder, usually the top level of your project folder:$ cd /projects/rawrdemo $ jruby –S rawr install
This command creates two files: build_configuration.yaml and src/org/rubyforge/rawr/Main.java, a Java class that instantiates a JRuby runtime and executes your Ruby application’s script. Copy your JRuby application’s files into the newly created src folder. If your project depends upon custom Java classes, package those class files into a JAR file and place your project JAR file along with any JAR files upon which your application depends in the lib/java folder. You must also have the jruby-complete.jar file in the lib/java folder.Open the build_configuration.yaml file and set theproject_nameparameter to the name you would like for the final executable. Change themain_ruby_fileparameter to the application’s main execution script name or rename the file to the default script name, main.rb. shows a sample configuration file.Example . Example Rawr configuration file# Name of the created jar file project_name: jruby_cookbook_app # Ruby file to invoke when jar is started main_ruby_file: jruby_cookbook_main
Executable JAR
Run therawr:jarRake task to generate an executable JAR file:$ jruby –S rake rawr:jar
The resulting files can found in the package/deploy directory. This includes the main executable JAR file jruby_cookbook_app.jar, a configuration file, and the JRuby runtime JAR file. You will need to include all the files in the folder along with the JAR files when you distribute your application. To test the JAR file, run:$ java –jar package/deploy/jruby_cookbook_app.jar
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Packaging JRuby Web Start Applications
- InhaltsvorschauYou want to package your JRuby program as a Java Web Start application.Install the Rawr gem. See for instructions on how to use and configure the gem. Because of the Web Start security model and JRuby’s use of the VM, the main JAR file and the JRuby runtime JAR file must be signed to run in the Web Start security sandbox. Start by generating a keystore file named myKeystore with the alias
myself. Enter a password and other information when prompted:$ keytool -genkey -keystore myKeystore -alias myself Enter keystore password: dumbpassword What is your first and last name? [Unknown]: Henry Liu What is the name of your organizational unit? [Unknown]: Global Digital What is the name of your organization? [Unknown]: MTV Networks What is the name of your City or Locality? [Unknown]: New York What is the name of your State or Province? [Unknown]: NY What is the two-letter country code for this unit? [Unknown]: US Is CN=Henry Liu, OU=Global Digital, O=MTV Networks, L=New York, ST=NY, C=US correct? [no]: yes Enter key password for <myself> (RETURN if same as keystore password):
Using your newly created keystore, create a self-signed certificate with theselfcertoption:$ keytool -selfcert -alias myself -keystore myKeystore
Edit the build_configuration.yaml file and create a hash namedweb_startcontaining the keyself_signwith the valuetrueand aself_sign_passphrasekey whose value is set to the certificate’s password. Create a hash namedjnlpwith the required values forcodebase,description,vendor, andhomepage_href. shows how to define YAML hashes in your configuration file.Example . Web Start parameters in Rawr configuration fileweb_start: { self_sign: true, self_sign_passphrase: password } jnlp: { codebase: http://localhost:8080, description: My Webstart Demo, vendor: Your Name, homepage_href: http://www.ora.com }Sign the JRuby runtime JAR file and other included JAR files that access the native system, use network services, or produce security errors:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating JRuby Applets
- InhaltsvorschauYou want to create a Java applet using JRuby.Working with an applet in JRuby is slightly different from creating a desktop application because the Ruby code cannot instantiate its own main application window but must add components to the parent applet’s content pane. One possible solution, shown in , is to expose the content pane as a global variable to the JRuby runtime.Example . JRuby applet with content pane in a global variable
JRubyApplet.java package org.jrubycookbook; import java.util.ArrayList; import org.jruby.Ruby; import org.jruby.javasupport.*; import java.awt.Container; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.*; public class JrubyApplet extends javax.swing.JApplet { public void init(){ Ruby runtime = JavaEmbedUtils.initialize(new ArrayList<String>()); runtime.evalScriptlet("require \"java\"\nclass FreshForJava\nend\n"); final IRubyObject blankRuby = runtime.evalScriptlet("FreshForJava.new"); IRubyObject globValue = JavaUtil.convertJavaToRuby(runtime, this.getContentPane()); globValue = Java.java_to_ruby(blankRuby, globValue, Block.NULL_BLOCK); GlobalVariable gv = new GlobalVariable(runtime, "$content_pane", globValue); runtime.defineVariable(gv); String bootRuby = "require 'appletmain' \n"; runtime.evalScriptlet( bootRuby ); } } appletmain.rb include Java import javax.swing.JPanel import javax.swing.JButton jp = JPanel.new but = JButton.new("OK") but.add_action_listener do |evt| puts "pressed" end jp.add(but) $content_pane.add(jp)
Package the Ruby scripts with your Java classes into a JAR file and then reference that JAR file from inside an HTMLapplettag. Include the jruby-complete.jar with the JRuby runtime along with your application JAR file through thearchiveparameter. shows a sampleapplettag to be used in an HTML page.Example . Applet tag for a JRuby applet<applet width="200" height="200" align="baseline" code="org.jrubycookbook.JrubyApplet.class" codebase="." pluginspage="http://java.sun.com/j2se/1.6.0/download.html" archive="jrubyapplet.jar,jruby-complete.jar"> </applet>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Manipulating Images
- InhaltsvorschauYou want to resize or otherwise modify an image using JRuby.Use a JRuby-compatible image library such as RMagick4J or ImageVoodoo for simple tasks like thumbnail generation. The Java 2D API can be used when you need more advanced image-processing capabilities.
RMagick4J
RMagick is a gem frequently used by Ruby developers for thumbnail generation or image editing but it requires the C-based ImageMagick libraries. RMagick4J was created so JRuby developers could work with the familiar API and allow their existing application to remain compatible RMagic applications. Start by installing the gem:$ jruby -S gem install rmagick4j
demonstrates a simple thumbnail-creation operation. It also shows how to make the library compatible with the RMagick gem by using a small amount of platform-detection code to load the correct gem before including the appropriate gem.Example . Creating thumbnails with RMagick4Jrequire 'rubygems' gem defined?(JRUBY_VERSION) ? 'rmagick4j' : 'rmagick' require 'RMagick' include Magick img = Image.new "avatar.jpg" thumb = img.resize(0.25) thumb.write "avatar-thumb.jpg"
RMagick4J has implemented most, but not all, of the functions from the original gem. The team has stated though they have a goal to provide complete compatibility with the C-based RMagick gem in the future.ImageVoodoo
ImageVoodoo was created by JRuby core team members Tom Enebo and Nick Sieger. Its original purpose was to be an API-compatible JRuby implementation of Ryan ImageScience library, another widely used Ruby library for image processing. by installing the ImageVoodoo gem:$ jruby -S gem install image_voodoo
shows how to create a thumbnail image using the library.Example . Creating thumbnails with ImageVoodoorequire 'image_voodoo' ImageVoodoo.with_image('logo-240-480.jpg') do |img| img.thumbnail(240) do |img| img.save "logo-120-240.jpg" end endThe ImageVoodoo gem includes the image_science.rb file to provide compatibility with existing ImageScience code. If you open the file, you’ll see thatEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating SWT Applications
- InhaltsvorschauYou want to create SWT applications using JRuby. The Standard Widget Toolkit (SWT) is probably the most popular Java client technology after the AWT and Swing libraries. It is open source software and is best known as the user interface framework used throughout the Eclipse IDE.Download the SWT library and include the swt.jar in your classpath or use the
requiremethod to load the JAR file from your Ruby application. JRuby integrates nicely with theorg.eclipse.swt.Shellandorg.eclipse.swf.widgets.Displayclasses and is able to access all the UI widgets in the library. The code in demonstrates how to handle button events in an SWT application.Example . Simple JRuby SWT applicationinclude Java require 'swt' import org.eclipse.swt.SWT import org.eclipse.swt.layout.RowLayout import org.eclipse.swt.widgets.Listener d = org.eclipse.swt.widgets.Display.new s = org.eclipse.swt.widgets.Shell.new(d) but = org.eclipse.swt.widgets.Button.new(s, SWT::PUSH) but.text = "Search" l = org.eclipse.swt.widgets.Label.new(s,SWT::NONE) l.text = "Click to Search" l.set_size(100,75) but.addListener(SWT::Selection, Listener.impl do |method, evt| l.text = 'searching...' end) s.layout = RowLayout.new s.set_size(300,200) s.open while(!s.is_disposed) do d.sleep if(!d.read_and_dispatch) end d.disposeThe Glimmer project is a JRuby DSL for creating SWT applications using a declarative syntax. It was created by Andy Maleh and is an official Eclipse project. Install the Glimmer gem with this command:$ jruby –S gem install glimmer
The gem provides a custom DSL for composing SWT applications. It has a declarative style, using keywords and accompanying blocks to define containers as well as individual components. The widget’s models and event handlers can be associated to Ruby methods for custom event processing and state changes. You can see an example of the Glimmer DSL in .Example . Writing an SWT application with Glimmerinclude Java require File.dirname(__FILE__) + "/../src/swt" include Glimmer import 'org.eclipse.swt.layout.GridLayout' def user_name "default text" end def enabled true end @shell = shell { text "SWT" composite { layout GridLayout.new(2, false) #two columns with differing widths label { text "Hello World!"} text { text bind(self, :user_name) enabled bind(self, :enabled) } } } @shell.openEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Accessing the Native Desktop
- InhaltsvorschauYou want to create or communicate with a native application.You can access a limited set of commonly used features in the native desktop through the
java.awt.Desktopclass introduced in Java 6. TheDesktopclass does not provide access to the entire desktop, but does allow you to perform common desktop activities such as opening the default browser, launching the default mail client, as well as printing or opening a file with its default application ().Example . Java Desktop APIinclude Java import java.awt.Desktop import java.net.URI import java.io.File d = Desktop::desktop # Open the browser d.browse(URI.new("http://www.ora.com/")) if d.isSupported(Desktop::Action::BROWSE) # Open your mail client and compose a message d.mail(URI.new("mailto:jruby@ora.com")) if d.isSupported(Desktop::Action::MAIL) # Launch the default jpg viewing application d.open(File.new("conference_pic_1.jpg")) if d.isSupported(Desktop::Action::OPEN) # Print a document d.print(File.new("directions.twxt")) if d.isSupported(Desktop::Action::PRINT)Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Accessing the System Tray
- InhaltsvorschauYou want to use JRuby to create an application that runs in the Mac OS X, Windows, or KDE system tray.
Swing
You can access the Windows or Linux system tray through the Javajava.awt.SystemTrayclass, added in Java 6, as in .Example . A Java system tray applicationinclude Java import java.awt.TrayIcon import java.awt.event.MouseListener if (java.awt.SystemTray::isSupported()) tray = java.awt.SystemTray::system_tray image = java.awt.Toolkit::default_toolkit.get_image("tray.gif") popup = java.awt.PopupMenu.new exititem = java.awt.MenuItem.new("Exit") exititem.addActionListener {java.lang.System::exit(0)} oraitem = java.awt.MenuItem.new("Go To ORA") oraitem.addActionListener do java.awt.Desktop::desktop.browse(java.net.URI.new("http://www.ora.com")) end popup.add(exititem) popup.add(oraitem) trayIcon = TrayIcon.new(image, "Tray Demo", popup) trayIcon.image_auto_size = true trayIcon.addActionListener do |evt| trayIcon.displayMessage("Action","Tray Action!", \ TrayIcon::MessageType::WARNING) end trayIcon.addMouseListener(MouseListener.impl do |method, evt| puts "mouse event #{method.to_s}" end tray.add(trayIcon) endSWT
The SWT library also includes a class for accessing the system tray:org.eclipse.swt.widgets.Tray(). This SWT widget has the advantage of being available on the Windows, Linux, and Mac platforms. The OS X implementation places an icon in the desktop’s status area.Example . SWT system tray applicationinclude Java require 'swt-debug' import org.eclipse.swt.SWT import org.eclipse.swt.widgets.Listener import org.eclipse.swt.widgets.MenuItem d = org.eclipse.swt.widgets.Display.new s = org.eclipse.swt.widgets.Shell.new(d) image = org.eclipse.swt.graphics.Image.new(d, "tray.gif") tray = d.system_tray item = org.eclipse.swt.widgets.TrayItem.new(tray, SWT::NONE) item.tool_tip_text = "SWT TrayItem" item.addListener(SWT::DefaultSelection, Listener.impl do |evt| puts("default selection") end) menu = org.eclipse.swt.widgets.Menu.new(s, SWT::POP_UP) menuitem = MenuItem.new(menu, SWT::PUSH) menuitem.text = "Exit" menuitem.addListener(SWT::Selection, Listener.impl do |method, evt| s.close end) item.addListener(SWT::MenuDetect, Listener.impl do |method, evt| menu.visible = true end) item.image = image # exclude these parameters to hide the main window #s.setBounds(10, 10, 100,100) #s.open() while(!s.is_disposed) do d.sleep if(!d.read_and_dispatch) end image.dispose d.disposeEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Swing Development with JRuby Domain-Specific Languages
- InhaltsvorschauThe trend toward declarative GUI design can be seen in the growth of web applications and the transition of established technologies to declarative models such as Adobe Flex and JavaFX Script. You want to use a JRuby-based DSL to develop your Swing .There are a several different projects that present DSLs for creating Swing user .
Swiby
The Swiby project is a JRuby adaptation of the declarative GUI building portion of the JavaFX Script language. Install the Swiby gem:$ jruby –S gem install swiby
Swiby’s syntax and design is inspired from JavaFX Script, in which blocks are used to represent hierarchies of user interface containers and components. Properties are defined by single-line name-value declarations. The Swing and AWT class names are mapped to shorter, more concise names used in the DSL. Swiby eliminates some of JavaFX Script’s capitalization when defining widgets and trailing colons after property declarations. shows Swiby in action.Example . Simple Swiby applicationrequire 'rubygems' require 'swiby' require 'swiby/form' class LabelModel attr_accessor :text end model = LabelModel.new model.text = "Click to Search" f = frame { title "Swiby Example" width 300 height 100 content { panel :layout => :flow do button("Search") { model.text="Searching...."} label {label bind(model, :text)} end } } f.visible = trueThe Swiby project has some features that aren’t found in JavaFX Script, like the ability to define your styles in an external file. The styles can be loaded and applied with the simpleuse_stylesdeclaration. shows how to alter the font by creating and loading a file named styles.rb.Example . Defining Swiby stylesswibyapp.rb frame { title "Swiby Example" width 300 height 74 use_styles "styles.rb" . . styles.rb create_styles { label( :font_family => Styles::VERDANA, :font_style => :italic, :font_size => 14, :color => 0xAA0000 ) }
The gem also provides a useful form-building DSL. This is geared toward forms with simpler, grid-based layouts.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using the Monkeybars Framework for Swing Development
- InhaltsvorschauYou want to develop a Swing application while following the model-view-controller (MVC) pattern.Use Monkeybars, a library created by David Koontz, the author of Rawr. It uses the MVC design pattern, similar to web frameworks like Rails or Struts, to create JRuby client applications. Start by installing the Monkeybars gem:
$ jruby –S gem install monkeybars
The gem will add the Monkeybars tool to your JRuby execution path. This is similar to the rails command used by Ruby on Rails developers. Running monkeybars creates the main project folder and the project skeleton:$ jruby –S monkeybars search_demo
includes a Java class that we will use with Monkeybars. This class extendsJFrameand contains a button with some accompanying text. The file should be located in the src.Example . Java GUI class for use with Monkeybarsimport javax.swing.*; public class SearchDemoJava extends JFrame { private JLabel message = new JLabel("Click to search"); private JButton search = new JButton("Search"); public SearchDemoJava(){ this.setLayout(new java.awt.FlowLayout()); this.setSize(300,100); add(search); add(message); } }The event-handling code and model data is defined in Ruby code. ThegenerateRake task, which was added along with the Monkeybars JAR file and several Ruby classes when the project was generated, is used to create the new model, view, and controller classes. Use theALLparameter to create all these at once:$ cd search_demo $ jruby –S rake generate ALL="src/search" (in C:/projects/search_demo) Generating controller SearchController in file search_controller.rb Generating model SearchModel in file search_model.rb Generating view SearchView in file search_view.rb
The model class uses an instance variable to store messages that are displayed in the text label (). The variable is later mapped to a GUI component in the complementing view file.Example . Monkeybars model fileclass SearchModel attr_accessor :search_message def initialize @search_message = "Starting" end endEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating Qt Applications with JRuby
- InhaltsvorschauYou would like to use JRuby to build applications using the Qt GUI framework. Qt is a popular cross-platform application framework for creating user interfaces. It has a rich set of components such as the Web Browser and System Tray widgets.The Qt Jambi project lets developers leverage the Qt framework through Java. Qt Jambi is available for download from http://trolltech.com/downloads/. Download the bundle and add the files qtjambi-version.jar and qtjambi-platform-version.jar to your classpath.Qt::JRuby is a library that brings several nice integration features when working directly with the Qt Jambi library from JRuby including a DSL for Qt. To use Qt::JRuby, you need to build the library from source. First, get the latest version of Qt::JRuby from its Git repository. Then, use Rake to build qtjruby-core.jar and install the wrapper :
$ git clone git://github.com/nmerouze/qtjruby.git Initialize qtjruby/.git Initialized empty Git repository in /home/henry/qtjruby/.git/ remote: Counting objects: 391, done. remote: Compressing objects: 100% (182/182), done. Receiving objects: 100% (391/391), 59.30 KiB | 78 KiB/s, done. Resolving deltas: 100% (180/180), done. $ cd qtjruby/qtjruby-core $ jruby –S rake (in /home/henry/qtjruby/qtjruby-core) ant -lib /opt/jruby-1.1.2/bin/../lib Buildfile: build.xml qtjruby-core: [javac] Compiling 14 source files to C:\home\devel\qtjruby\qtjruby-core\build [javac] Note: Some input files use unchecked or unsafe operations. [javac] Note: Recompile with -Xlint:unchecked for details. [jar] Building jar: C:\home\devel\qtjruby\qtjruby-core\lib\qtjruby-core.ja r BUILD SUCCESSFUL Total time: 1 second WARNING: no rubyforge_project specified WARNING: RDoc will not be generated (has_rdoc == false) Successfully built RubyGem Name: qtjruby-core Version: 0.2.0 File: qtjruby-core-0.2.0.gem /opt/jruby-1.1.2/bin/../bin/jruby -S gem install pkg/qtjruby-core-0.2.0.gem Successfully installed qtjruby-core-0.2.0 1 gem installed
The Qt::JRuby library includes a Ruby module namedEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 6: Build Tools
- InhaltsvorschauJust about every software project, regardless of language or scope, needs to be built in some way. The build process can include steps including compiling code, running tests, file processing, packaging, and deployment, among others. Because there is significant commonality among build processes, a variety of specialized build systems are available. These systems allow you to describe your build process as a series of interdependent, reusable tasks. Ant, for example, allows you to replace this:
$ javac *.java $ jar –cf my.jar *.class
With this:$ ant jar
Or even (ifjaris the default target):$ ant
This chapter discusses techniques for building Java-based projects. In this context, Ruby can be used as the core of the build process or to enhance an existing build process. There are two major build systems used for Java projects: Ant and Maven. Both of these are projects of the Apache Software Foundation and both have extension mechanisms that support JRuby. This is the focus of the first few recipes. The later recipes describe two different Ruby-based build systems designed for Java projects: Raven and Buildr. All four of these build systems have merit: which to use for a particular project is largely a matter of preference. Raven and Buildr are significantly newer than Ant and Maven and, as a result, the communities around them are smaller.The chapter ends with two recipes about the Hudson continuous integration server. The first of these addresses how to build Ruby projects that use the Rake build system. The second looks at using Ruby to add additional scripting to your build process inside Hudson.You are using Apache Ant as a build system and need to add some logic to your build that isn’t easily accomplished with Ant’s XML syntax.Add the appropriate JRuby dependencies to Ant’s lib directory and use thescripttask to include Ruby code inside your Ant build file. shows a very simple usage of this task.Example . Hello World from JRuby inside Ant<?xml version="1.0" encoding="UTF-8"?> <project name="project" default="package"> <target name="simple"> <script language="ruby"> print "Hello World!" </script> </target> </project>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Introduction
- InhaltsvorschauJust about every software project, regardless of language or scope, needs to be built in some way. The build process can include steps including compiling code, running tests, file processing, packaging, and deployment, among others. Because there is significant commonality among build processes, a variety of specialized build systems are available. These systems allow you to describe your build process as a series of interdependent, reusable tasks. Ant, for example, allows you to replace this:
$ javac *.java $ jar –cf my.jar *.class
With this:$ ant jar
Or even (ifjaris the default target):$ ant
This chapter discusses techniques for building Java-based projects. In this context, Ruby can be used as the core of the build process or to enhance an existing build process. There are two major build systems used for Java projects: Ant and Maven. Both of these are projects of the Apache Software Foundation and both have extension mechanisms that support JRuby. This is the focus of the first few recipes. The later recipes describe two different Ruby-based build systems designed for Java projects: Raven and Buildr. All four of these build systems have merit: which to use for a particular project is largely a matter of preference. Raven and Buildr are significantly newer than Ant and Maven and, as a result, the communities around them are smaller.The chapter ends with two recipes about the Hudson continuous integration server. The first of these addresses how to build Ruby projects that use the Rake build system. The second looks at using Ruby to add additional scripting to your build process inside Hudson.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Adding Ruby Scripting to Ant Builds
- InhaltsvorschauYou are using Apache Ant as a build system and need to add some logic to your build that isn’t easily accomplished with Ant’s XML syntax.Add the appropriate JRuby dependencies to Ant’s lib directory and use the
scripttask to include Ruby code inside your Ant build file. shows a very simple usage of this task.Example . Hello World from JRuby inside Ant<?xml version="1.0" encoding="UTF-8"?> <project name="project" default="package"> <target name="simple"> <script language="ruby"> print "Hello World!" </script> </target> </project>This task can use either the Bean Scripting Framework (BSF) or the Java Scripting (JSR 223) libraries discussed in and, as a result, supports many more scripting languages than just Ruby. To use this task, you must make the appropriate dependencies available to Ant. For BSF, these dependencies are jruby.jar and bsf.jar, both included in the JRuby distribution’s lib directory. For Java Scripting, you need the jruby.jar file from the JRuby distribution and jruby-engine.jar, available from https://scripting.dev.java.net/. and contain more information about these APIs. As mentioned in the Solution above, these JAR files can be placed in Ant’s lib directory. Alternatively, the dependencies can be declared inside the Ant build file as seen in . This latter method requires slightly more configuration, as you need to set up the appropriate Ant properties—jruby.homeandjsr223.engines.homein the case of . In this example, those properties are defined in a build.properties file in the user’s home directory.Example . Defining JRuby dependencies inside the Ant file<?xml version="1.0" encoding="UTF-8"?> <project name="project" default="package"> <property file="${user.home}/build.properties" /> <path id="jruby"> <fileset file="${jruby.home}/lib/jruby.jar" /> <fileset file="${jsr223.engines.home}/lib/jruby-engine.jar" /> </path> <target name="simple"> <script language="ruby" classpathref="jruby"> print "Hello #{$project.getProperty('user.name')}" </script> </target> </project>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using Ruby in Ant Conditions
- InhaltsvorschauYour Ant build has some conditional execution that is best expressed with Ruby code.Set up the Ant classpath as described in and use the
scriptconditionAnt condition element. This element is set up similar to the script task described in . The key distinction is that conditions are evaluated to produce a Boolean result. Typically, the condition has a default value and the content of the condition would override this as necessary. For example, the Ant fragment in will set a property nameduser_has_text_filestotrueif the user has any text files in their home directory.Example . Using scriptcondition<target name="setup"> <condition property="user_has_text_files"> <scriptcondition language="ruby" value="false"> cwd = Dir.pwd Dir.chdir $project.getProperty("user.home") $self.setValue(true) if Dir.glob("**/*.txt") Dir.chdir cwd </scriptcondition> </condition> </target>In , the default result of the condition isfalse. This result is overridden totrueby using the$selfvariable, which represents the condition object itself. As with the script task discussed in , the$projectvariable is set to the AntProjectobject and all Ant properties are available as variables in the Ruby script.Ant conditions can be combined withand,or,not, andxorcondition elements. shows the combination of the condition from with one of Ant’s built-in conditions,os. In this example, we ensure that theuser_has_text_filesproperty is only set on Windows systems.Example . Combining scriptcondition with other Ant conditions<target name="setup"> <condition property="user_has_text_files"> <and> <os family="windows"/> <scriptcondition language="ruby" value="false"> puts "hello" cwd = Dir.pwd Dir.chdir $project.getProperty("user.home") $self.setValue(true) if Dir.glob("**/*.txt") Dir.chdir cwd </scriptcondition> </and> </condition> </target>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Writing an Ant Task in Ruby
- InhaltsvorschauYou want to execute a Ruby script in multiple Ant build files.Use Ant’s
scriptdeftask to create a new task definition that executes a Ruby script. Thescriptdeftask has a child element namedattribute, which can be used to pass attributes into the task. defines an Ant task namedstart-webrickthat can be used to start up an instance of the WEBrick HTTP server given a specific port number and document root.Example . Using scriptdef to define a new Ant task<?xml version="1.0" encoding="UTF-8"?> <project name="project" default="start"> <scriptdef name="start-webrick" language="ruby"> <attribute name="port"/> <attribute name="root"/> <![CDATA[ require 'webrick' include WEBrick server = HTTPServer.new(:Port => $attributes.get('port').to_i) server.mount("/", HTTPServlet::FileHandler, $attributes.get('root')) server.start ]]> </scriptdef> <target name="start"> <start-webrick port="8000" root="${basedir}/files"/> </target> </project>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Adding Ruby Scripting to Maven Builds
- InhaltsvorschauYou are using Apache Maven as a build system and need to quickly add some additional steps to your build process.Configure the JRuby Maven plugin in your Maven project definition file, pom.xml. shows the use of this plugin. In this example, the plugin’s
rungoal, which executes a Ruby script, is bound to theprocess-resourcesphase. This means that the inline Ruby script will be run before any compilation or tests occur.Example . Using the JRuby Maven plugin<project> <modelVersion>4.0.0</modelVersion> <groupId>org.jrubycookbook</groupId> <artifactId>maven-sample</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>jruby-maven-plugin</artifactId> <executions> <execution> <phase>generate-resources</phase> <goals> <goal>run</goal> </goals> <configuration> <ruby> require 'fileutils' FileUtils.touch 'target/timestamp' </ruby> </configuration> </execution> </executions> <!— These are necessary due to an issue with JRuby's Maven distribution. --> <dependencies> <dependency> <groupId>backport-util-concurrent</groupId> <artifactId>backport-util-concurrent</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>asm</groupId> <artifactId>asm-all</artifactId> <version>2.2.3</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Writing a Maven Plugin with JRuby
- InhaltsvorschauYou are using Apache Maven as a build system and want to reuse some Ruby script across different projects. A good example of this is to use the RedCloth Ruby library for generating project documentation using the Textile markup language.Create a new Maven plugin project and add the dependencies discussed in to both the project and the
maven-plugin-pluginplugin. contains a simple pom.xml project descriptor.Example . Maven pom.xml file for a JRuby-based Maven plugin<project> <modelVersion>4.0.0</modelVersion> <groupId>org.jrubycookbook</groupId> <artifactId>maven-textile-plugin</artifactId> <packaging>maven-plugin</packaging> <version>1.0-SNAPSHOT</version> <name>Maven Textile Plugin</name> <description> Generates site documentation from Textile sources using RedCloth. </description> <dependencies> <dependency> <groupId>org.codehaus.mojo</groupId> <artifactId>jruby-maven-plugin</artifactId> <version>1.0-beta-4</version> </dependency> <dependency> <groupId>backport-util-concurrent</groupId> <artifactId>backport-util-concurrent</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>asm</groupId> <artifactId>asm-all</artifactId> <version>2.2.3</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-plugin-plugin</artifactId> <dependencies> <dependency> <groupId>org.codehaus.mojo</groupId> <artifactId>jruby-maven-plugin</artifactId> <version>1.0-beta-4</version> </dependency> <dependency> <groupId>backport-util-concurrent</groupId> <artifactId> backport-util-concurrent </artifactId> <version>3.0</version> </dependency> <dependency> <groupId>asm</groupId> <artifactId>asm-all</artifactId> <version>2.2.3</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Building Java Projects with Raven
- InhaltsvorschauYou need to build a Java project and wish to write your build script using Ruby rather than XML.Use Raven, a build tool for Java project that is based on Ruby’s Rake tool. Raven is essentially an add-on to Rake that provides Rake with additional Rake tasks to build Java projects. Raven is available as a RubyGem, so to install it simply run:
$ gem install raven
To use Raven, create a file named Rakefile in the root of your project and include all necessary tasks in this file. contains the simplest of Raven build scripts.Example . Simple Raven build scriptrequire 'raven' javac 'compile'
This script would be executed by running:$ rake compile
Or:$ jruby -S rake compile
This will compile all the Java files in a directory named src/main/java, following the Maven project convention (see upcoming sidebar). This default can be easily overridden, as seen in .Example . Changing the default source directoryrequire 'raven' javac 'compile' do |t| t.build_path << "src/java" endBecause Raven is based on Rake, any existing Rake task can be used within a Raven build. A good example of this is thecleantask. Since Rake includes a clean task, Raven doesn’t need to provide one, as seen in .Example . Raven build with Rake tasksrequire 'raven' require 'rake/clean' CLEAN.include('target') javac 'compile'Note that Raven actually doesn’t require JRuby.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Referencing Libraries with Raven
- InhaltsvorschauYou are using Raven to build your Java project and depend upon other libraries, such as those from Jakarta Commons.Use the
dependencyRaven task to define a set of dependencies and then reference the set from the tasks that need the dependencies. contains a Rakefile for a project that depends upon Jakarta Commons Logging and Jakarta Commons HttpClient. The dependency on the HttpClient library is restricted to version 3.1 by using the=>operator.Example . Rakefile with dependencies1 require 'raven' 2 3 dependency 'compile_deps' do |t| 4 t.deps << ['commons-logging', {'commons-httpclient' => '3.1'}] 5 end 6 7 javac 'compile' => 'compile_deps' 8 9 javadoc 'jdoc' => 'compile_deps'When used in a task definition, as on lines 7 and 9 of , the=>operator establishes a dependency between tasks.Raven uses the RubyGems packaging system to manage dependencies by wrapping JAR files into a RubyGem. In order to avoid, in the words of the Raven source code, polluting the regular local RubyGem repository, defined by the GEM_HOME environment variable, Raven stores its RubyGems in a .raven subdirectory of the user’s home directory. As discussed in the sidebar within , it is possible to populate this directory with the contents of a local Maven repository by running:raven import
The Raven team makes a public gem repository available at http://gems.rubyraven.org/ that contains wrapped versions of all of the libraries in the central Maven repository (http://repo1.maven.org/maven2/). It is possible to set up your own private repository, as we’ll see in the next recipe.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Hosting a Private Raven Repository
- InhaltsvorschauYou are building a Java project with Raven and want to insulate your build process from any external network problems.Create a private Raven repository by importing content from a Maven repository. This can be done with a few simple commands:
# Change /home/raven below to whatever directory you want to use. $ mkdir /home/raven $ cd /home/raven $ raven repository $ raven server
This will import all artifacts from the central Maven repository and then start a web server on port 2233. To reference this repository in your Rakefile, add this line after the require statements:set_sources(["http://localhost:2233"])
The repository command used above has a few interesting options. First, it is possible to restrict the import to a subset of the repository by passing a list of project identifiers to the command. For example, to import only Jakarta Commons HttpClient and JUnit, you would run:$ raven repository commons-httpclient junit
It is also possible to import a different Maven repository using the-moption. For example, to import JBoss’s Maven repository, run:$ raven –m http://repository.jboss.com/maven2/ repository
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Running JUnit Tests with Raven
- InhaltsvorschauYou are building your Java project with Raven and want to execute some JUnit unit tests.Place your unit tests in the src/test/java directory, create a
dependencytask for any test dependencies, and then use thejunitRaven task as seen in . By default, Raven will search for classes whose names start withTest, but in , this default is overridden to include only those classes with names ending withTest.Example . Unit testing with Ravenrequire 'raven' dependency 'compile_deps' do |t| t.deps << ['commons-logging', {'commons-httpclient' => '3.1'}] end dependency 'test_deps' => 'compile_deps' do |t| t.deps << {'junit' => '3.8.2'} end javac 'compile' => 'compile_deps' junit 'test' => ['compile', 'test_deps'] do |t| t.test_classes << "**/*Test.java" endYou will see the test results on the console. If the tests pass, you’ll see an OK message:$ rake test (in /home/justin/raven-sample1) ... Running test org.jrubycookbook.SomeTest . Time: 0 OK (1 test)
A test failure will include the stack trace:$ rake test (in /home/justin/raven-sample1) ... Running test org.jrubycookbook.SomeTest .F Time: 0 There was 1 failure: 1) testTest(org.jrubycookbook.SomeTest)junit.framework.AssertionFailedError at org.jrubycookbook.SomeTest.testTest(SomeTest.java:8) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl. java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces sorImpl.java:25) FAILURES!!! Tests run: 1, Failures: 1, Errors: 0 There were failures!- JUnit website, http://www.junit.org
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Building Java Projects with Buildr
- InhaltsvorschauYou need to build a Java project and wish to define your project’s build using Ruby rather than XML.Use Buildr, a declarative build system for Java code written in Ruby. Buildr is available as a RubyGem; installation can be done by running:
$ gem install buildr
Buildr uses a file named buildfile to define a project. A minimal buildfile such as the one seen in defines the project’s name (line 11), the project’s group (line 13), a description of the project (line 10), the current version of the project (line 12), and the packaging type of the project (line 14).Example . Minimal Buildr buildfile10 desc "The Chapter 6 buildr project" 11 define "ch06-buildr" do 12 project.version = "1.0" 13 project.group = "org.jrubycookbook" 14 package(:jar) 15 end
Based on this buildfile, Buildr will assume that this is a project containing Java sources in a directory named src/main/java and JUnit test cases in a directory named src/test/java. The generated JAR file will be named ch06-buildr-1.0.jar. To build the project (which for Buildr means compiling the source code and running the tests), simply run:$ buildr
To build the JAR file, run:$ buildr package
These commands can be run in the project’s root directory or any subdirectory.If you have an existing Java project, especially one that uses Maven as its build system, Buildr can automatically create this file for you. Runbuildrfrom the project’s root directory and select the appropriate option:$ buildr To use Buildr you need a buildfile. Do you want me to create one?: 1. From maven2 pom file 2. From directory structure 3. Skip ? 1 Created /home/edelsonj/kramer/buildfile
When creating a buildfile from an existing Maven project’s pom.xml file, Buildr is able to extract all of the information seen in as well as all of the project’s dependencies. The importer can be a little over-enthusiastic when it comes to dependencies, so always check the resulting buildfile. If your Maven project includes submodules, the generatedEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Referencing Libraries with Buildr
- InhaltsvorschauYou are using Buildr to build your Java project and depend upon other libraries, such as those from Jakarta Commons.Pass the list of dependencies to the
compile.withmethod. Each dependency is defined by four attributes: group, name, packaging type, and version. For example, if your code depends upon Apache HttpClient and Jakarta Commons Logging, you would specify:compile.with "org.apache.httpcomponents:httpclient:jar:4.0-alpha4", "org.apache.httpcomponents:httpcore:jar:4.0-beta1", "commons-logging:commons-logging:jar:1.1.1"
Buildr will look for dependencies in your local Maven repository (in the .m2/repository subdirectory of your home directory). If it cannot find the dependencies there, it will attempt to download them from a remote repository. As a result, it is also necessary to add this line to your buildfile:repositories.remote << "http://repo1.maven.org/maven2/"
Buildr’s dependency mechanism is entirely based upon the Maven repository structure. Unlike Raven, which uses a RubyGems-based dependency mechanism, any library in an existing Maven repository can be used as part of a Buildr build. This includes the libraries in the central repository (at http://repo1.maven.org/maven2/), as well as other public Maven repositories hosted by Sun (http://download.java.net/maven/2/) and JBoss (http://repository.jboss.com/maven2/), among others. Individual developers and software development organizations can also host private Maven repositories.Although Buildr will sometimes correctly resolve dependencies transitively, this functionality does not always work. Expect support for transitive dependencies to improve in upcoming versions.- Introduction to Maven Repositories, http://maven.apache.org/guides/introduction/introduction-to-repositories.html
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Building with Rake Inside Hudson
- InhaltsvorschauYou want to build a software project that uses Rake as its build system in a continuous manner. This could be on a schedule (i.e., every day at noon) or upon every submission to a version control system like Subversion.Use a continuous integration server that supports Rake, such as Hudson. Once the Hudson Rake plugin is installed, you can simply add a Rake execution to your job, as in .
Figure : Rake build step in Hudson job configurationTo install the Rake plugin in Hudson, use the Hudson Plugin Manager, which can be found under the Manage Hudson menu. Inside the Plugin Manager, select the Available tab to see the list of available plugins. Check the box next to the Rake plugin listing () and click the Install button. After the plugin has been installed, you will need to restart Hudson.
Figure : Rake plugin entry in the Plugin ManagerHudson’s Rake plugin allows you to configure multiple Ruby runtimes. This allows you to have some projects built against MRI and some projects built against JRuby within the same continuous integration server. This is done through the System Configuration screen, seen in .
Figure : Multiple Ruby runtimes in Hudson- Hudson website, https://hudson.dev.java.net/
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Adding Ruby Script to a Hudson Job
- InhaltsvorschauYou have some additional build steps that need to be done as part of your build process when executed through the Hudson continuous integration server.Use the Hudson Ruby plugin. This plugin allows you to add arbitrary Ruby script as a build step in your job. shows a job with two build steps. The first executes the Ant target named
warand the second runs some Ruby code that copies all WAR files into a temporary directory.
Figure : Using the Hudson Ruby pluginAs with the Rake plugin discussed in , the Ruby plugin can be downloaded and installed through Hudson’s Plugin Manager. Unlike the Rake plugin, the Ruby plugin does not support multiple runtimes. It will only execute therubycommand on your PATH. Thus, if want to use this plugin with JRuby, it will be necessary to create a copy (or symbolic link) of the jruby script included with the JRuby distribution named ruby and ensure that this script is on your PATH before any other Ruby. The plugin does make debugging simple by outputting the Ruby version number in the build’s console output, like this:[workspace] $ ruby -v /tmp/hudson35926.rb ruby 1.8.5 (2007-09-24 patchlevel 114) [i386-linux]
Hudson makes a number of environment variables available to Ruby scripts executed in this manner. These include the name of the job (JOB_NAME), the build number (BUILD_NUMBER), and the Hudson URL (HUDSON_URL). A full listing is available through the Hudson web interface.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 7: Testing
- InhaltsvorschauThe focus of this chapter is the topic of automated testing, specifically, testing Java code with Ruby. There are several key advantages of using a dynamic language, such as Ruby, to test code written in a statically typed language, such as Java:
- Automated test cases tend to require a lot of bootstrapping code. Using a domain-specific language (DSL) such as those provided by the Ruby frameworks like dust and Expectations can cut down on this repetitive code.
- Dynamic languages make it very easy to create mock objects. JRuby, for example, allows you to directly instantiate Java interfaces.
- Open classes allow code to be modified at runtime to facilitate testing.
There are a variety of testing frameworks available in Ruby, the most popular of which are wrapped into a JRuby-based project called JtestR. JtestR is an open source project that Ola Bini and Anda Abramovici, developers at ThoughtWorks, started in 2008 with the purpose of making it easy to test Java code with a variety of Ruby testing frameworks. As of the current version 0.3, JtestR includes support for:- Test/Unit
- RSpec
- Expectations
- dust
- Mocha
In addition, JtestR supports the Java testing frameworks JUnit and TestNG, making it a “one-stop shop” for testing frameworks.JtestR is available for download from http://jtestr.codehaus.org.You want to test your Java code using a more concise syntax than is available from Java testing frameworks such as JUnit and TestNG, but with a minimal learning curve for developers familiar with JUnit.Use JtestR’s support for the Ruby testing framework Test/Unit. Test/Unit uses similar semantics to JUnit: test cases extend a specific test case class and test methods follow a naming convention. In the case of Test/Unit, test cases must extendTest::Unit::TestCaseand test methods are prefixed withtest_. shows a simple Test/Unit class that tests thesize()method ofjava.util.ArrayList.Example . Simple Test/Unitclass TestArrayList < Test::Unit::TestCase def test_that_size_method_works list = java.util.ArrayList.new assert_equal(0, list.size) list << 'first' list << 'second' assert_equal(2, list.size) end endEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Introduction
- InhaltsvorschauThe focus of this chapter is the topic of automated testing, specifically, testing Java code with Ruby. There are several key advantages of using a dynamic language, such as Ruby, to test code written in a statically typed language, such as Java:
- Automated test cases tend to require a lot of bootstrapping code. Using a domain-specific language (DSL) such as those provided by the Ruby frameworks like dust and Expectations can cut down on this repetitive code.
- Dynamic languages make it very easy to create mock objects. JRuby, for example, allows you to directly instantiate Java interfaces.
- Open classes allow code to be modified at runtime to facilitate testing.
There are a variety of testing frameworks available in Ruby, the most popular of which are wrapped into a JRuby-based project called JtestR. JtestR is an open source project that Ola Bini and Anda Abramovici, developers at ThoughtWorks, started in 2008 with the purpose of making it easy to test Java code with a variety of Ruby testing frameworks. As of the current version 0.3, JtestR includes support for:- Test/Unit
- RSpec
- Expectations
- dust
- Mocha
In addition, JtestR supports the Java testing frameworks JUnit and TestNG, making it a “one-stop shop” for testing frameworks.JtestR is available for download from http://jtestr.codehaus.org.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Unit Testing Java Code with Test/Unit
- InhaltsvorschauYou want to test your Java code using a more concise syntax than is available from Java testing frameworks such as JUnit and TestNG, but with a minimal learning curve for developers familiar with JUnit.Use JtestR’s support for the Ruby testing framework Test/Unit. Test/Unit uses similar semantics to JUnit: test cases extend a specific test case class and test methods follow a naming convention. In the case of Test/Unit, test cases must extend
Test::Unit::TestCaseand test methods are prefixed withtest_. shows a simple Test/Unit class that tests thesize()method ofjava.util.ArrayList.Example . Simple Test/Unitclass TestArrayList < Test::Unit::TestCase def test_that_size_method_works list = java.util.ArrayList.new assert_equal(0, list.size) list << 'first' list << 'second' assert_equal(2, list.size) end endLike JUnit, Test/Unit supports the use of a setup method (namedsetup) into which you can extract code that needs to be executed prior to each test. For example, if a second test method was added to , it would make sense to put the creation of the newArrayListinstance into thissetupmethod, as seen in .Example . Test/Unit class with setup methodclass TestArrayList < Test::Unit::TestCase def setup @list = java.util.ArrayList.new end def test_that_size_method_works assert_equal(0, @list.size) @list << 'first' @list << 'second' assert_equal(2, @list.size) end def test_that_empty_works assert(@list.empty) @list << 'first' @list << 'second' assert(!@list.empty) end endTest/Unit also supports the use of a method namedteardownfor cleanup after each test is run.Test/Unit tests can be run without any additional configuration with JtestR. Simply place the test class files in a directory named test/unit and start JtestR’s command-line test runner. This class, along with all of JtestR’s dependencies can be found in the JtestR JAR file, available from the JtestR website. You can run the JtestR command-line test runner with the command:Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Unit Testing Java Code with dust
- InhaltsvorschauYou want to test your Java code using a more concise syntax than is available from Java testing frameworks such as JUnit and TestNG, and find Test/Unit to be too verbose.Use Jay Fields’s dust library, support for which is included with JtestR. dust provides an alternate syntax for writing tests that takes advantage of Ruby language features to create a domain-specific language (DSL) for testing. contains the dust version of the tests in .Example . Unit testing with dust
unit_tests do test "that size method works" do @list = java.util.ArrayList.new assert_equal(0, @list.size) @list << 'first' @list << 'second' assert_equal(2, @list.size) end test "that empty method works" do @list = java.util.ArrayList.new assert @list.empty @list << 'first' @list << 'second' assert !@list.empty end endAs with Test/Unit tests, dust tests can be run through JtestR with no special .Under the covers, dust converts the body of the block passed to theunit_testsmethod into a Ruby class in theUnitsmodule. The name is derived from the filename. If was contained in a file named lists_test.rb, the generated class would beUnits::ListsTests. Each call to the test method is converted to a method in this generated class. The name of the method is derived from the name given. The generated class for includes methods namedtest_that_size_method_worksandtest_that_empty_method_works.In addition to theunit_testsmethod seen in , dust also supports afunctional_testsmethod. The only difference between the two methods is that tests within thefunctional_testsmethod are placed in a class in theFunctionalsmodule.Under the default JtestR configuration, these generated class and method names are only seen when a test fails. For example:Failure: test_that_size_method_works(Units::ListTests) ... <2> expected but was <3>.
Unlike Test/Unit, dust does not supportsetuporteardownmethods.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Unit Testing Java Code with Expectations
- InhaltsvorschauYou want to test your Java code using a more concise syntax than is available from Java testing frameworks such as JUnit and TestNG and want to ensure you follow some testing best practices, specifically limiting the number of assertions per test to one.Use JtestR’s support for the Expectations framework. Like dust, Expectations provides a domain-specific language (DSL) for writing tests. Unlike dust, Expectations does not use the standard Test/Unit assertion methods. Instead, each test makes an assertion about the return value of the test. contains the same tests seen in prior recipes using Expectations.Example . Unit testing with Expectations
Expectations do expect 0 do list = java.util.ArrayList.new list.size end expect 2 do list = java.util.ArrayList.new list << 'first' list << 'second' list.size end expect true do list = java.util.ArrayList.new list.empty end expect false do list = java.util.ArrayList.new list << 'first' list << 'second' list.empty end endJtestR’s support for Expectations is not automatic; it must be enabled through configuration. To do so, first determine the naming convention you will use for Expectations-based tests. Then create a file named jtestr_config.rb in the test directory of your project. This file should contain a line such as the following:expectation Dir["test/expectations/*.rb"]
In this case, we declare that any file in the test/expectations directory is meant to be run with Expectations. You could also use a filename-based naming convention:expectation Dir["test/**/*_expect.rb"]
Or even declare individual files:expectation Dir["test/unit/list_tests_expect.rb"]
The output of Expectations is different than that for Test/Unit or dust tests, but the information conveyed is similar:Expectations .F.F Finished in 0.00206 seconds Failure: 2 failed, 0 errors, 2 fulfilled --Failures-- file </home/justin/list-tests/test/expectations/test.rb> line <7> expected: <3> got: <2> file </home/justin/list-tests/test/expectations/test.rb> line <19> expected: <true> got: <false>
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Testing Java Code with RSpec
- InhaltsvorschauYou want to write behavior-orientated tests for your Java code.Use JtestR’s support for the RSpec Behavior-Driven Development (BDD) framework. RSpec is actually composed of two different frameworks for writing tests: the Spec framework and the Story framework.
Spec framework
RSpec Spec tests describe the behavior of an object through a series of assertions about the behavior of the object. These assertions are referred to as examples. The Spec file in describes the behavior of thejava.util.HashSetclass.Example . RSpec Spec file for java.util.HashSetimport java.util.HashSet describe HashSet do before(:each) do @set = HashSet.new end it "should be empty" do @set.should be_empty end it "should be of size one after an item is added" do @set << "foo" @set.size.should == 1 end it "should be of size one after an item is added twice" do @set << "foo" @set << "foo" @set.size.should == 1 end it "should be of size two after two items are added" do @set << "foo" @set << "bar" @set.size.should == 2 end endBy default, JtestR will execute files in any test directory whose filenames end with _spec.rb as an RSpec Spec file. If you place the file from in the unit directory and execute the command-line test runner, you will see output like this:$ java org.jtestr.JtestRRunner Unit Spec: 4 examples, 0 failures, 0 errorsStory framework
RSpec stories are generally composed of two files; one that describes the behavior of an object in more-or-less plain text, referred to as the story, and another that translates the behavior descriptions in the first file into method calls on the actual object, referred to as the steps. For example, contains a story that describes the behavior of theretains()method ofjava.util.ArrayListand contains the steps corresponding to this story. These files are associated with the block at the end of the steps file.Example . Story about java.util.ArrayListEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Creating Mock Objects with Mocha
- InhaltsvorschauYou want to test a Java class that has dependencies on other classes and want to insulate your tests from changes in the behavior of those other classes.Use Mocha, a Ruby mocking and stubbing framework that is included with JtestR. Mocha allows you to create instances of Java interfaces and classes that exhibit a specific behavior. Mock objects can be used in any type of test supported by JtestR. In , Mocha is used to create a mock instance of
java.util.Collection, which is passed to an instance ofjava.util.ArrayList. This test validates the behavior of theretainAll()method, specifically that it calls thecontains()method on the suppliedCollectionobject the correct number of times.Example . Unit test with dust and Mochaunit_tests do test "that retainAll only calls contains" do list = java.util.ArrayList.new list << 'first' list << 'second' list << 'third' other = java.util.Collection.new other.expects(:contains).returns(true).times(3) list.retainAll(other) end endIf anotherothermethod is called on theCollectionobject, an exception will be thrown and the test will fail. For example, ifjava.util.ArrayListimplemented theretainsAll()method by iterating through the collection, this error would be output:#<Mock:0x4f4>.contains - expected calls: 1, actual calls: 0
Meaning that the mock expected thecontains()method to be called, but that did not occur.Mocha can also specify the set of parameters to expect. This feature can be used to enhance the test in to test thatArrayListcalls thecontains()methods in the proper sequence. This new test can be seen in .Example . Expecting a specific parameterunit_tests do test "that retainAll calls contains once per item in the list" do list = java.util.ArrayList.new list << 'first' list << 'second' list << 'third' other = java.util.Collection.new other.expects(:contains).with('first').returns(true) other.expects(:contains).with('second').returns(true) other.expects(:contains).with('third').returns(true) list.retainAll(other) end endEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Modifying the JtestR Classpath
- InhaltsvorschauYou need to test classes that are not available on JtestR’s default classpath. By default, JtestR’s classpath includes the following directories:
- build/classes
- build/test_classes
- target/classes
- target/test_classes
The default classpath also includes all JAR files in the lib and build_lib directories (and any subdirectories).Use the JtestR configuration file, by default named jtestr_config.rb and placed in the test directory, to define the correct classpath. For example, to set the classpath to be the bin directory, your configuration file would contain:classpath 'bin'
Multiple classpath definitions can be included in the configuration file.Using theclasspathconfiguration option as described above will overwrite the default classpath. To add the default entries back, put this line to your configuration file:add_common_classpath true
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Grouping Tests for JtestR
- InhaltsvorschauYou have a number of tests run through JtestR and want to group them.Follow JtestR’s directory naming conventions to group your tests. Within the main test directory, JtestR will automatically group your tests based on the directory they are in and will execute these groups in a particular order:
- Unit tests, those in the unit directory.
- Functional tests, those in the functional directory.
- Integration tests, those in the integration directory.
- Other tests, those that are not in the unit, functional, or integration directories.
The tests within each of these directory-based groups are then further grouped based on the testing framework used. When you run the test runner and have tests in multiple groups, you will see the test results grouped:Unit TestUnit: 4 test, 0 failures, 0 errors Integration TestUnit: 2 test, 0 failures, 0 errors
Here we see that there were four tests in the unit directory and two tests in the integration directory, all of which used Test/Unit.Although JtestR provides these automatic directory-based groups, there is nothing actually different about the environment under which unit tests run as compared with functional or integration tests.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using the JtestR Command-Line Options
- InhaltsvorschauYou want to customize the behavior of the JtestR command-line test runner in some way, such as limiting the tests to be run or enabling additional logging.The JtestR command-line test runner has a number of options that can be configured through command-line arguments. Unfortunately these arguments must be passed in a specific sequence that you must adhere to:
port- This argument, which defaults to
22332, allows you to connect the test runner to a long-lived server process. This reduces the amount of time required to perform a test run. This capability is discussed in . tests- This argument, which defaults to
test, specifies the top-level directory in which test group directories can be found. logging- This argument specifies the logging level for JtestR. Possible values are
NONE,ERR,WARN,INFO, andDEBUG. The default isWARN. configFile- This argument specifies the filename of the JtestR configuration file.
outputLevel- This argument specifies how much information about each test is output. Possible values are
NONE,QUIET,NORMAL,VERBOSE, andDEFAULT. output- This argument provides JtestR with the output location. The default is
STDOUT. groups- This argument defines the test group (or groups, in which case they should be comma-delimited) that will be run. The default is to run all tests discovered.
One typical use of these arguments is to output the name of each test as it is run. As you can see from the output above, by default, JtestR only outputs an individual test name if something goes wrong. By setting theoutputLevelargument toVERBOSE, you can have it output each test name:$ java org.jtestr.JtestRRunner 22332 test WARN jtsetr_config.rb VERBOSE test_that_empty_works(TestArrayList): . test_that_size_method_works(TestArrayList): . Unit TestUnit: 1 test, 0 failures, 0 errors- ”
- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Running JtestR with Ant
- InhaltsvorschauYou are building a project with Apache Ant and want to add tests written in Ruby.Use the Ant task provided with JtestR. This can be done by adding the following task definition to your Ant build.xml file:
<taskdef name="jtestr" classname="org.jtestr.ant.JtestRAntRunner" classpath="lib/jtestr-0.3.jar" />
Then call this task from inside an Ant target:<target name="test"> <jtestr /> </target>This target can then be run from the command line:$ ant test
The JtestR Ant task supports all of the options used by the command-line test runner (see ). For example, to turn on verbose output, your target would look like this:<target name="test"> <jtestr outputLevel="VERBOSE" /> </target>In addition to the command-line options, there is afailOnErroroption that defaults totrue. Use this option if you want the Ant build to continue even if the tests fail.- Ant website, http://ant.apache.org/
- ”
- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Running JtestR with Maven
- InhaltsvorschauYou are building a project with Maven and want to add tests written in Ruby.Use the Maven plugin provided with JtestR. This can be done by adding the following plugin reference to your pom.xml file:
<plugin> <groupId>org.jtestr</groupId> <artifactId>jtestr</artifactId> <version>0.3</version> <executions> <execution> <goals> <goal>test</goal> </goals> </execution> </executions> </plugin>Once this is in place, JtestR will automatically run whenever Maven’s test phase is executed.Unfortunately, the latest release (0.3) of JtestR’s Maven support has a dependency on a nonstandard JRuby library. As a result, when you try to use the plugin, you may see this error:[ERROR] BUILD ERROR [INFO] -------------------------------------------------------------- [INFO] Failed to resolve artifact. Missing: ---------- 1) org.jruby:jruby-complete:jar:r6947 Try downloading the file manually from the project website. ... ---------- 1 required artifact is missing. for artifact: org.jtestr:jtestr:maven-plugin:0.3
To correct this, download the JAR from http://dist.codehaus.org/jtestr/jruby-complete-r6947.jar and install it into your local Maven repository. This can be done with these commands:$ wget http://dist.codehaus.org/jtestr/jruby-complete-r6947.jar $ mvn install:install-file -Dfile=jruby-complete-r6947.jar -Dversion=r6947 \ -DartifactId=jruby-complete -Dpackaging=jar -DgroupId=org.jruby
The JtestR Maven plugin supports all of the options used by the command-line test runner (see ). For example, to only run unit tests, your plugin configuration would look like this:<plugin> <groupId>org.jtestr</groupId> <artifactId>jtestr</artifactId> <version>0.3</version> <executions> <execution> <goals> <goal>test</goal> </goals> </execution> </executions> <configuration> <groups>Unit TestUnit</groups> </configuration> </plugin>In addition to the command-line options, there is aEnde der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Improving JtestR Performance
- InhaltsvorschauYou are using JtestR and want to accelerate the execution times of your unit tests.Start a JtestR server in the background. This can be done with the class
org.jtestr.BackgroundServer:$ java org.jtestr.BackgroundServer
By default, this will create a server on port 22332 with two runtimes, meaning that two sets of tests can be run simultaneously. To change these options, you can use command-line arguments: the port followed by the number of runtimes. For example, to start five runtimes listening on port 1000 you would run:$ java org.jtestr.BackgroundServer 1000 5
Note that if you deviate from the default port, you will need to specify this when you start the test runner. For example, with the command-line test runner, this is the first option:$ java org.jtestr.JtestRRunner 1000
JtestR also includes classes that allow this test server to be run from inside an Ant or Maven build. For Ant, this is done with theJtestRAntServerclass:<target name="server"> <taskdef name="jtestr-server" classname="org.jtestr.ant.JtestRAntServer" classpath="lib/jtestr-0.3.jar" /> <jtestr-server /> </target>For Maven, if you have the JtestR Maven plugin configured in your pom.xml, you can start the server by running this on the command line:$ mvn jtestr:server
- ”
- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Chapter 8: The JRuby Community
- InhaltsvorschauThis final chapter includes a series of recipes about how to participate in the JRuby community. First, we will look at building JRuby from source, something that most developers looking to peek under the covers of JRuby will need to do at some point. We will also do a quick walkthrough of JRuby’s issue management system before finishing up with some information about the ways in which JRuby community members communicate with each other.You need to build JRuby from the source files. This could be to take advantage of some unreleased code or to create a JRuby JAR file for distribution.Download the source using a Subversion client:
$ svn co http://svn.codehaus.org/jruby/trunk/jruby/
JRuby is built using Apache Ant. There are a number of useful Ant targets in the provided build script:jar- Creates the jruby.jar file.
jar-complete- Creates the jruby-complete.jar file, which includes all of the contents from jruby.jar and all of the Ruby standard libraries.
test- Runs the JRuby unit test suite.
dist-bin- Creates the JRuby binary distribution, i.e., the ZIP file that you download from http://dist.codehaus.org/jruby/.
The Subversion command above will check out the most recent version of the source code (the trunk) from the JRuby repository. However, some times it is necessary to check out the source core that corresponds to a release. This can be done by checking out one of the tags under http://svn.codehaus.org/jruby/tags/. For example, the source of the JRuby 1.1 release can be found at http://svn.codehaus.org/jruby/tags/jruby-1_1/.The Ant script also includes two targets that relate to JRuby’s compatibility with other Ruby interpreters. Although there is no formal language specification for Ruby, a wide-ranging test suite has been created as part of the Rubinius project. JRuby’s Ant script includes the following targets that relate to these specifications:spec- Test all of the released specifications that JRuby is known to be able to pass.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Introduction
- InhaltsvorschauThis final chapter includes a series of recipes about how to participate in the JRuby community. First, we will look at building JRuby from source, something that most developers looking to peek under the covers of JRuby will need to do at some point. We will also do a quick walkthrough of JRuby’s issue management system before finishing up with some information about the ways in which JRuby community members communicate with each other.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
- Building JRuby from Source
- InhaltsvorschauYou need to build JRuby from the source files. This could be to take advantage of some unreleased code or to create a JRuby JAR file for distribution.Download the source using a Subversion client:
$ svn co http://svn.codehaus.org/jruby/trunk/jruby/
JRuby is built using Apache Ant. There are a number of useful Ant targets in the provided build script:jar- Creates the jruby.jar file.
jar-complete- Creates the jruby-complete.jar file, which includes all of the contents from jruby.jar and all of the Ruby standard libraries.
test- Runs the JRuby unit test suite.
dist-bin- Creates the JRuby binary distribution, i.e., the ZIP file that you download from http://dist.codehaus.org/jruby/.
The Subversion command above will check out the most recent version of the source code (the trunk) from the JRuby repository. However, some times it is necessary to check out the source core that corresponds to a release. This can be done by checking out one of the tags under http://svn.codehaus.org/jruby/tags/. For example, the source of the JRuby 1.1 release can be found at http://svn.codehaus.org/jruby/tags/jruby-1_1/.The Ant script also includes two targets that relate to JRuby’s compatibility with other Ruby interpreters. Although there is no formal language specification for Ruby, a wide-ranging test suite has been created as part of the Rubinius project. JRuby’s Ant script includes the following targets that relate to these specifications:spec- Test all of the released specifications that JRuby is known to be able to pass.
spec-all- Test all of the released Ruby specifications.
spec-show-excludes- List the specifications that JRuby is known to not be able to pass.
spec-latest- Test all of the available Ruby specifications that JRuby is known to be able to pass, first obtaining the specification files from source control.
spec-latest-all- Test all of the available Ruby specifications, first obtaining the specification files from source control.
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Submitting an Issue Report for JRuby
- InhaltsvorschauYou have discovered a problem with JRuby or wish to request a feature to be added in a future version.JRuby uses Atlassian JIRA as its issue-tracking tool. You can view the list of issues and create new issue reports by going to http://jira.codehaus.org/browse/JRUBY. You can browse issues anonymously, but must register and log in before creating a new issue or commenting on an existing issue. Before creating an issue, please search previously submitted issues to avoid duplication.Assuming you want to create an issue and have logged in, click the Create New Issue link in the main navigation to start the issue creation process. shows the resulting dialog.
Figure : JIRA Create Issue dialogOnce you have selected the appropriate issue type and clicked Next, you should populate the following form with as much information as possible. This will assist JRuby developers in fully understanding the issue.At the bottom of the Issue Details form are two form fields, seen in , that provide you with an opportunity to prioritize the handling of your issue.
Figure : Testcase and Patch form fieldsThe first, “Testcase included,” allows you to specify that you have attached (or will attach) a test that demonstrates the issue in a repeatable manner. The ability to reliably reproduce an issue is vital to resolving it. The second, “Patch Submitted,” allows you to specify that you have attached (or will attach) a patch to the JRuby source that resolves the issue. It is common to create a patch against the latest source from version control, not the most recent release.- ”
Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar. - Using the JRuby Mailing Lists
- InhaltsvorschauYou need assistance with JRuby or a related tool.Subscribe to the JRuby User mailing list. Subscriptions are managed through Xircles, a project management system developed for use by the Codehaus. You can see the available JRuby mailing lists by going to http://xircles.codehaus.org/projects/jruby/lists. A searchable archive of the mailing list is also available on this page.In addition to the mailing lists, JRuby core developers can frequently be found in the #jruby IRC channel on irc.freenode.net. Conversations on this channel are logged and an archive is available through http://codingbitch.com/irc/channel?channel=%23jruby.Ende der Inhaltsvorschau. Der weiterere Inhalt dieses Abschnitts ist hier nicht einsehbar.
Zurück zu JRuby Cookbook
