JBoss.orgCommunity Documentation
This chapter shows you how to build a simple web application based on Sinatra. Althought the application itself is very small, it uses many TorqueBox features.
We will create an application called Poorsmatic, a "poor man's Prismatic". This is a truly awful content discovery service that merely returns URL's from Twitter that contain at least one occurrence of the search term used to find the tweets containing the URL's in the first place.
If you don't get it - don't worry - everything will be clear later.
We made the application source available for you in the TorqueBox git repository
in examples/poorsmatic/ directory. To get started you need to clone the repository.
$git clone git://github.com/torquebox/torquebox.gitCloning into 'torquebox'... remote: Counting objects: 77466, done. remote: Compressing objects: 100% (26065/26065), done. remote: Total 77466 (delta 37601), reused 76739 (delta 36971) Receiving objects: 100% (77466/77466), 47.06 MiB | 2.48 MiB/s, done. Resolving deltas: 100% (37601/37601), done
When not said otherwise every file location used in this guide will be relative to the examples/poorsmatic/
directory located under the checkout directory.

The main goal of the application is to grab tweets from Twitter stream. We'll use a
TwitterService implemented as TorqueBox service. The service itself will be instructed
in which keywords we're interested via terms topic. Received tweets will be scanned for URL's
and those URL's will be put into url's queue for processing. The URLScraper
will be responsible for visiting all URL's from the urls queue and counting the words
found in the <body/> tag on the page. Results will be put into
database. There will be also a web interface for viewing the URL's and editing the terms.
We use use Sinatra web framework for this application. This is a very simple DSL framework for writing web applications fast, which is a perfect choice in our case.
If you're new to Sinatra, the project homepage is a great resource to start. It has a lot of examples and pretty good documentation.
We choose PostgreSQL mainly because it has support for transactions which will be used in our application.
First please create a new user and database for the application.
$su postgres -c psqlpsql (9.2.2) Type "help" for help.postgres=#CREATE USER poorsmatic WITH PASSWORD 'poorsmatic';CREATE ROLEpostgres=#CREATE DATABASE poorsmatic;CREATE DATABASEpostgres=#GRANT ALL PRIVILEGES ON DATABASE poorsmatic to poorsmatic;GRANTpostgres=#\q
To connect to the database we need to use the md5 authentication method
instead of ident. To change it please open /var/lib/pgsql/data/pg_hba.conf
(location in Fedora operating system, may be different
if you use some other OS) file and make sure you use md5 method.
To be able to use TorqueBox transactions in /var/lib/pgsql/data/postgresql.conf please set
max_prepared_transactions to value greater than 0. In our case 10 should
be sufficient.
The object-relational mapper of our choice is DataMapper.
To see the configuration details please look at torquebox_init.rb.
Models are defined in the models/ directory.
Although in this quick overview of the app we will not discuss the database access and ORM you can always see the full code in the repository.
It's time to launch the application for the first time. First we need to
start TorqueBox by executing torquebox run command. The output
should be similar to this:
$torquebox run... 14:34:42,734 INFO [org.torquebox.jobs.as] Initializing TorqueBox Jobs Subsystem 14:34:42,735 INFO [org.torquebox.services.as] Initializing TorqueBox Services Subsystem 14:34:42,738 INFO [org.torquebox.core.as] Initializing TorqueBox Core Subsystem 14:34:42,740 INFO [org.torquebox.security.as] Initializing TorqueBox Auth Subsystem 14:34:42,740 INFO [org.torquebox.web.as] Initializing TorqueBox Web Subsystem 14:34:42,733 INFO [org.torquebox.cdi.as] Initializing TorqueBox CDI Subsystem 14:34:42,792 INFO [org.torquebox.stomp.as] Initializing TorqueBox STOMP Subsystem 14:34:42,791 INFO [org.projectodd.polyglot.stomp.as] Initializing Polyglot STOMP Subsystem 14:34:42,807 INFO [org.projectodd.polyglot.hasingleton.as] Initializing HA-Singleton Subsystem 14:34:42,808 INFO [org.projectodd.polyglot.cache.as] Initializing Polyglot Cache Subsystem 14:34:42,854 INFO [org.torquebox.core.as] Welcome to TorqueBox AS - http://torquebox.org/ 14:34:42,855 INFO [org.torquebox.core.as] version........... 2.2.0 14:34:42,856 INFO [org.torquebox.core.as] build............. 74 14:34:42,857 INFO [org.torquebox.core.as] revision.......... 530d7d30a5ba5ca953eba21b2aa6df1bf4022649 ... 14:35:02,072 INFO [org.jboss.as] (Controller Boot Thread) JBAS015961: Http management interface listening on http://127.0.0.1:9990/management 14:35:02,073 INFO [org.jboss.as] (Controller Boot Thread) JBAS015951: Admin console listening on http://127.0.0.1:9990 14:35:02,073 INFO [org.jboss.as] (Controller Boot Thread) JBAS015874: JBoss AS 7.1.x.incremental.129 "Arges" started in 21875ms - Started 281 of 400 services (118 services are passive or on-demand)
Now we're ready to deploy the application. To do so go to the examples/poorsmatic/ directory
and execute the torquebox deploy command:
$torquebox deployDeployed: poorsmatic-knob.yml into: /home/goldmann/work/torquebox-2.2.0/jboss/standalone/deployments
You can now reach your application on http://localhost:8080/poorsmatic/. If you see "Hello from Poorsmatic!" message it means that everything worked perfectly!
Congratulations! You have now a running web application. In the next steps we will discuss the TorqueBox features we used to build it. features.
In this section we'll discuss the basic TorqueBox features which made it possible to build the application.
Deployment descriptor is a file used to inform TorqueBox what kind of application it is or what features are used in it. There are two types of deployment descriptors: internal and external. Additionally you have the choice of using pure Ruby DSL or specify the options in YAML format. In our case we'll use Ruby DSL syntax. Please refer to TorqueBox manual if you want to read more about deployment descriptors.
TorqueBox does pretty good job at guessing what kind of application is the one we are trying to deploy. If it's a Rack based application - it'll be registered by default at the root context (/). We can change this (and many other things) by using a deployment descriptor.
As you can see we choose the /poorsmatic context which made it
possible to reach the application at
poorsmatic context.
This simple setting lets you deploy many applications on one TorqueBox server in different context roots.
In our application we use Twitter to receive tweets from the stream filtered by some keywords. The best way to run something constantly is to implement it as a TorqueBox service. Below you can find a simple skeleton.
Example 3.2. TorqueBox service skeleton
class AService
def initialize(credentials = {})
end
def start
end
def stop
end
end
The code is pretty self-explaining. The only thing you need to keep in mind is
that the start method is executed when you deploy the service. Similarly
the stop method is executed when you undeploy the service. As simple as that.
In our application we'll use the twitter4j4r Twitter client. Please don't ask about the name...
Example 3.3. twitter_service.rb
require 'twitter4j4r'
class TwitterService
...
def initialize(credentials = {})
@terms = []
@client = Twitter4j4r::Client.new(
:consumer_key => credentials['consumer_key'],
:consumer_secret => credentials['consumer_secret'],
:access_token => credentials['access_token'],
:access_secret => credentials['access_secret']
)
@client.on_exception do |exception|
puts "An error occured while reading the stream: #{exception.message}"
end
end
def start
@client.track(*@terms) do |status, client|
end
end
def stop
@client.stop
end
end
Now we need to inform TorqueBox that we want to deploy a service
implemented in TwitterService class. We need to do it in the
mentioned before torquebox.rb deployment descriptor.
You may also ask how do we inject the credentials required to connect to Twitter?
Yes, you're right, deployment descriptor.
Example 3.4. torquebox.rb
TorqueBox.configure do
...
service TwitterService do
name 'twitter-service'
config do
consumer_key 'Consumer key'
consumer_secret 'Consumer secret'
access_token 'Access token'
access_secret 'Access token secret'
end
end
end
Before you deploy the application make sure you use correct credentials. You can
generate them on the Twitter apps
page. Just create new application and you're ready to rock.
You may wonder how do we update the keyword list we want to watch on Twitter? We'll use messaging features of TorqueBox.
Messaging allows us to create loosely coupled applications. Using queues and topics aswell as message producers and consumers is very easy, so let's start right away! If you're new to the messaging terms, don't fear - take a look at the messaging section of TorqueBox manual.
We need to create one queue and a topic. We'll use the topic to send/receive keywords we want to watch on Twitter and the queue will be used to send urls from tweets containing one or more specified keywords. Creating them is very simple, we just need to add the queue and topic constructs to the deployment descriptor.
That's everything required to deploy a queue and topic with your application.
Both will be started when you deploy the application and stopped when you
undeploy it. Handy feature, isn't?
It's pretty easy to consume a message from a queue or topic. You can use message processors.
Example 3.6. term_consumer.rb
class TermConsumer < TorqueBox::Messaging::MessageProcessor
...
def on_message(message)
# do stuff here
end
end
A new message processor will be created for each message that arrives to the queue.
The message itself will be injected to the on_message method.
You can do whatever you want with it afterwards. In our case we want to update the
keywords in the twitter service. The easiest thing to do is to simply get access to the
service and execute an update method on it. Let's do it!
Example 3.7. term_consumer.rb
class TermConsumer < TorqueBox::Messaging::MessageProcessor
include TorqueBox::Injectors
def initialize
@twitter_service = fetch('service:twitter-service')
end
def on_message(terms)
@twitter_service.update(terms)
end
end
Each time a TermConsumer message processor is created TorqueBox will use its power to inject the
TwitterService service into the consumer. Afterwards the terms will be injected into the on_message
method and the update method will be executed on the service itself. The only thing
that left now is to show the update method in TwitterService class.
Example 3.8. twitter_service.rb
class TwitterService
def initialize(credentials = {})
@terms = []
...
end
def update(terms)
@terms = terms
stop
start
end
...
end
Execution of this method will update the terms list. Additionally the Twitter client
will be restarted to watch new keywords.
Last thing left to do is to wire the message consumer with the queue or topic. We use the deployment descriptor. Here is how to do it:
Example 3.9. torquebox.rb
TorqueBox.configure do
...
queue '/queues/urls' do
processor UrlScrapper do
concurrency 4
end
end
topic '/topics/terms' do
processor TermConsumer
end
...
end
You can ask yourself what concurrency parameter means. This tells
TorqueBox how many message processors of the selected type should be connected
to the selected queue. This is very handy if you expect to have many messages arriving
and needs more workers to process them.
You can find another message processor used to retrieve and parse web pages in
url_scrapper.rb file. Since URLScrapper
doesn't do anything fancy besides counting the words in <body> and
saving the result in a database we'll not go into discussing it this time, sorry.
You know now how to receive messages from topics (or queues), but the remaining question is how to put new messages into the queue? We'll look at it in this section.
The TwitterService besides retrieving tweets for particular keywords is also
supposed to pull out every link from the received tweets. These links will be put into a queue
for later processing.
We will use the twitter-text gem to retrieve the link.
Example 3.10. twitter_service.rb
require 'twitter-text'
class TwitterService
include TorqueBox::Injectors
...
def start
@client.track(*@terms) do |status, client|
urls = extract_urls(status.text)
unless urls.empty?
queue = fetch('/queues/urls')
urls.each do |url|
queue.publish(url)
end
end
end
end
...
end
For each received tweet we try to find an URL in it.
If we find at least one, we send this URL as a string to the queue. To do this
we inject first the queue and later we execute the publish method
on it. Easy.
The last feature of TorqueBox used in the presented application are distributed transactions. Distributed transaction ensure the atomicity of the execution. They can span across the whole application. For example a transaction could be started in the web layer and end in database. This is exactly how we use it in Poorsmatic!
Example 3.11. poorsmatic.rb
require 'torquebox'
require 'sinatra'
require 'haml'
require 'models/term'
class Poorsmatic < Sinatra::Base
include TorqueBox::Injectors
...
helpers do
def terms_changed
terms = []
Term.all.each {|t| terms << t.term}
topic = fetch('/topics/terms')
topic.publish(terms)
end
end
...
post '/terms' do
term = Term.new(:term => params[:term])
TorqueBox.transaction do
if term.save
terms_changed
else
session[:errors] = []
term.errors.each {|e| session[:errors] << e.first }
end
end
redirect to('/terms')
end
delete '/term/:id' do
TorqueBox.transaction do
Term.get(params[:id]).destroy
terms_changed
end
redirect to('/terms')
end
...
end
Look at the post '/terms' block. This code is executed when we try to save a new
term using the web page. First - we create a Term object, then we start
a transaction and try to save the object to the database. If the operation was
successfull we send a list of the terms (see terms_changed method)
as array to the /topic/terms topic.
The nice thing about transaction is that they're atomic. This means that if an error occurs in the transaction block, the transaction is rolled back and the state is restored. For example if an error occurs in our case during sending a message to the topic, the whole transaction is rolled back and the database state will be restored too!
You can find another usage of transaction in the delete '/term:id' block.
It'll make sure that we'll notify the terms queue only after successful removal of the term
from database.
Since distributed transactions is an advanced topic you can read about them in the TorqueBox manual. You'll find there more information about transactions itself or configuration options.
Congratulations! You know now many of TorqueBox features. There are still many to explore. To learn more about them just open the TorqueBox manual and use them.
Poorsmatic application was just a simple example. You can always go back to the source code and see again how it was done.