O'Reilly Emerging Telephony

oreilly.comSafari Books Online.Conferences.
advertisement
MySQL Conference and Expo April 14-17, 2008, Santa Clara, CA
AddThis Social Bookmark Button

Print Subscribe to Telephony Subscribe to Newsletters

Sophisticated Asterisk Development with Adhearsion
Pages: 1, 2, 3, 4

Database Integration

Though immensely successful in the web development space for serving dynamic content, database integration has always been an underused possibility for driving dynamic voice applications with Asterisk. Most Asterisk applications that do accomplish this outsource the complexity to a PHP or Perl AGI script because the extensions.conf or AEL grammars are simply impractical for the level of sophistication this requires.



Adhearsion uses a database integration library developed by the makers of the Ruby on Rails framework called ActiveRecord. With ActiveRecord, the end user seldom, if ever, writes SQL statements. Instead, the developer accesses the database just like any Ruby object. Because Ruby allows such flexible dynamism, the access to the database looks and feels quite natural. Additionally, ActiveRecord abstracts the differences between database management systems, making your database access implementation agnostic.

Without going too much into the internals of ActiveRecord and more sophisticated uses of it, let us consider the following simple MySQL schema:

CREATE TABLE groups (
    `id` int(11) DEFAULT NULL auto_increment PRIMARY KEY,
    `description` varchar(255) DEFAULT NULL,
    `hourly_rate` decimal DEFAULT NULL
);

CREATE TABLE customers (
    `id` int(11) DEFAULT NULL auto_increment PRIMARY KEY,
    `name` varchar(255) DEFAULT NULL,
    `phone_number` varchar(10) DEFAULT NULL,
    `usage_this_month` int(11) DEFAULT 0,
    `group_id` int(11) DEFAULT NULL
);

In practice we would obviously store much more information about the customer and keep the service usage information in a database-driven call detail record but this degree of simplicity helps demonstrate ActiveRecord fundamentals more effectively.

To connect Adhearsion with this database, one simply specifies the database access information in a YAML configuration file like so:

adapter: mysql
host: localhost
database: adhearsion
username: root
password: pass

This tells Adhearsion how to connect to the database, but how we access information in the tables depends on how we model our ActiveRecord objects. Since an object is an instance of a class, we write a class definition to wrap around each table. We define simple properties and relationships in the class with the superclass's methods.

Here are two classes we may use with the aforementioned tables:

class Customer < ActiveRecord::Base
  belongs_to :group

  validates_presence_of   :name, :phone_number
  validates_uniqueness_of :phone_number
  validates_associated    :group

  def total_bill
    self.group.hourly_rate * self.usage_this_month / 1.hour
  end
end

class Group < ActiveRecord::Base
  has_many :customers
  validates_presence_of :description, :hourly_rate  
end

From just this small amount of information, ActiveRecord can make a lot of logical inferences. When these classes interpret, ActiveRecord assumes the table names to be customers and groups respectively by lowercasing the classes' names and making them plural. If this convention is not desired, the author can easily override it. Additionally, at interpretation time, ActiveRecord actually peeks into the database's columns and makes available many new dynamically created methods.

The belongs_to and has_many methods in this example define relationships between Customers and Groups. Notice again how ActiveRecord uses pluralization to make the code more expressive in the has_many :customers line. From this example we also see several validations—policies, which ActiveRecord will enforce. When creating a new Customer we must provide a name and phone_number at the bare minimum. No two phone numbers can conflict. Every Customer must have a Group. Every Group must have a description and hourly_rate. These help both the developer and the database stay on track.

Also, notice the total_bill method in the Customer class. On any Customer object we extract from the database, we can call this method which multiplies the hourly_rate value of the group to which the Customer belongs by the Customer's own phone usage this month (in seconds).

Below are a few examples that may clarify the usefulness of having Ruby objects abstract database logic.

everyone = Customer.find :all

jay = Customer.find_by_name "Jay Phillips"
jay.phone_number # Performs a SELECT statement
jay.total_bill   # Performs arithmetic on several SELECT statements
jay.group.customers.average :usage_this_month

jay.group.destroy
jay.group = Group.create :description => "New cool group!",
                         :hourly_rate => 1.23
jay.save

Because the database integration here becomes much more natural, Asterisk dial plans becomes much more expressive as well. The following is an example dial plan of a service provider that imposes a time limit on outgoing calls using information from the database.

# Let's assume we're offering VoIP service to customers
# whom we can identify with their callerid. 
service {
  # The line of code below performs an SQL SELECT
  # statement on our database. The find_by_phone_number()
  # method was created automatically because ActiveRecord
  # found a phone_number column in the database. Adhearsion
  # creates the "callerid" variable for us.
  caller = Customer.find_by_phone_number callerid

  usage = caller.usage_this_month
  if usage >= 100.hours
    play "sorry-cant-let-you-do-that"
  else
    play %w'to-hear-your-account-balance press-1 
            otherwise wait-moment'
    choice = wait_for_digit 3.seconds

    if choice == 1
      charge = usage / 60.0 * caller.group.hourly_rate
      play %W"your-account will-reflect-charge-of $#{charge}
              this month for #{usage / 60} minutes and
              #{usage % 60} seconds"
    end

    # We can also write back to the "usage_this_month"
    # property of "caller". When the time method finishes,
    # the database will be updated for this caller.
    caller.usage_this_month += time do
      # Code in this block is timed.
      dial IAX/'main-trunk'/extension
    end
    caller.save
  end
}

Robust database integration like this through Adhearsion brings new ease to developing for and managing a PBX. Centrally persistent information allows Asterisk to integrate with other services cleanly while empowering more valuable services whose needs are beyond that of traditional Asterisk development technologies.

Pages: 1, 2, 3, 4

Next Pagearrow




Search Emerging Telephony

Search

Tagged Articles

Be the first to post this article to del.icio.us

Sponsored Resources

  • Inside Lightroom
Advertisement
Sign up today to receive special discounts,
product alerts, and news from O'Reilly.
Privacy Policy >
View Sample Newsletter >
  • Youtube
  • http://www.youtube.com/OreillyMedia
  • Twitter
  • Subscribe
  • View All RSS Feeds >
O'Reilly Media

800-889-8969 or 707-827-7019
Monday-Friday 7:30am-5pm PT
©2011, O'Reilly Media, Inc.
All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.
  • About O'Reilly
  • Academic Solutions
  • Contacts
  • Customer Service
  • Careers
  • Press Room
  • Privacy Policy
  • Terms of Service
  • Writing for O'Reilly
  • Community
  • Authors
  • Forums
  • Membership
  • Newsletters
  • RSS Feeds
  • User Groups
  • Partner Sites
  • makezine.com
  • makerfaire.com
  • craftzine.com
  • igniteshow.com
  • PayPal Developer Zone
  • O'Reilly Insights on Forbes.com