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.