Skip navigation

RhoMobile Blogs

11 Posts authored by: Kutir Mobility

This the second of three articles on how RhoConnect can be combined with various platforms such as Ruby on Rails, .NET, and Java.

The Rho platform was developed as a cross-platform solution that offers powerful tools for uniting enterprise data with mobile devices. One key part of that strategy is the RhoConnect sync server platform. RhoConnect offers an easy-to-implement way of keeping the data on the mobile device and your back end storage synchronized.

As Motorola states:

RhoConnect is the first of a new category of “mobile app integration” servers. Using RhoConnect drastically simplifies the development of connectivity to an enterprise backend app. The RhoConnect server and built-in RhoConnect client in the smartphone app perform all the work to get data down to the device. This eliminates 50 to 80 percent of the development effort in enterprise smartphone apps: performing the backend application integration.

-- http://docs.rhomobile.com/en/5.0.0/rhoconnect/introduction

There are several ways to interface your back end systems to RhoConnect (and indirectly your mobile devices). It's up to you, as the developer, to choose the best method suited to your needs:

1. RhoConnect REST API

RhoConnect has a REST API that allows direct and custom services to be developed with it as the platform. The API allows you to tie in complicated back end systems by giving you direct control of the RhoConnect service. This means your solution can be as simple or as complicated as you wish it to be.

2. RhoConnect Source Adapters

A RhoConnect source adapter gives you a framework that encapsulates the RhoConnect API, but gives you the leeway to include your own business logic through models and controllers. The source adapter is a good choice if you wish to have a framework to automate the actual communication with RhoConnect, yet maintain the ability to inject custom business logic into the process.

3. RhoConnect Plugins

From Motorola:

Rhoconnect Plugins allow you to connect your backend apps seamlessly with rhoconnect. You can write the source (query, create, update and delete operations) into a backend application, and use a RhoConnect plugin in the language that matchs your backend application, such as Java or .NET."

A Rhoconnect plugin encapsulates the integration of your back end solution and RhoConnect in a library that handles the communication seamlessly. You simply implement your application's models and through the plugin RhoConnect will automatically synchronize your data across your mobile devices.

RhoConnect plugin

-- Image from Motorola: (http://docs.rhomobile.com/en/5.0.0/rhoconnect/net-plugin)

In this article we're going to examine how to implement a RhoConnect plugin using Microsoft's .NET framework as the back end application. .NET provides an excellent framework for developing enterprise applications that communicate with a variety of database engines, such as Azure and SQL Server. The RhoConnect plugin will connect our .NET application data to a Rhodes mobile application transparently.

To demonstrate RhoConnect plugins we're going to use three different apps:

  • A RhoConnect server
  • A .NET MVC 4 Application that will act as our primary application and database server
  • A Rhodes mobile app (using the RhoSimulator)

We're using Windows 8.1 as the development platform in this exercise. Visual Studio and RhoStudio are excellent platforms to develop the server and mobile applications respectively.The tools you'll need are:

  • RhoStudio (5.0)
  • Visual Studio Express (2013 used in this case)

For our example we're going to set up a very simple address book. It will allow the end user to view a set of addresses, along with names and email addresses associated with those addresses. We will be able to update this list of names from both the mobile device and the .NET back end. Let's get started!

The Setup

We're going to emulate the Internet on our local computer, meaning our applications will all be on localhost. In a production or staging environment your RhoConnect and MVC app will be hosted on an application server, while your Rhodes app will reside on a mobile device such as an iPhone or Android device.

The first thing we need to do is to install the RhoMobile Suite. This will install this will install the basic toolchain we'll need to build and run RhoMobile apps. You can download the latest version of RhoMobile Suite athttps://developer.motorolasolutions.com/community/rhomobile-suite. Follow the installation steps and install all of the components.

Let's create a root directory and create all of our applications as subdirectories from this root.

mkdir plugins

cd plugins

The source code for all the programs created in this article are available on Github at https://github.com/richard-kutir/net-plugin.

Our Server Application

In order to demonstrate the RhoConnect plugin we're going to create a simple MVC 4 web application using Visual Studio. Open Visual Studio and create a new C# Web Project within our plugins folder. Name it AddressBook. Let's also set the default port for our debugging web server to 3000 by right clicking on the project name in our Solution Explorer and choosing Properties > Web > Servers and making our URL http://localhost:3000. It is important to know what port the application is communicating on. By setting it we'll know the actual port to use when we configure RhoConnect.

Imgur

Once you've created your project, we need to add a reference to the RhoConnect library that will allow us to connect our .NET application to our mobile client. You can download the project from Github using:

 git clone https://github.com/rhomobile/rhoconnect.NET.git 

Or download the zip file from https://github.com/rhomobile/rhoconnect.NET/archive/master.zip

Inside the project's bin/Release folder is the file RhoconnectNET.dll. Add a reference to your newly created MVC app to this .DLL by right-clicking on References and selecting "Add Reference..." the click the "Browse" button. Navigate to where you've downloaded the .DLL and click "Add". This will add the reference to your application.

Imgur

Now create a new Address class and scaffold the controllers and views. We'll use this to both allow us to manage the Address database on the server-side as well as facilitate communication with the RhoConnect server.

Within our .NET application create a new Address class within the Models directory:

using System.Data.Entity;

 

namespace AddressBook.Models {

    public class Address {

          public int ID { get; set; }

          public string Name { get; set; }

          public string Address1 { get; set; }

          public string Email { get; set; }

 

          public class AddressDBContext : DbContext {

              public DbSet<Address> Addresses { get; set; }

          }

    }

}

This is the basic schema that we will use with our application: a name, an address, and an email address, all strings.

Using this new model use the Add > New Scaffolded Item to add a new MVC Controller with views, using Entity Framework. Select the Address class as the model and use the name AddressesController for the controller. This will quickly create the views and the controller to allow our model to be accessible in our application.

Imgur

Within our controller we implement our connection to RhoConnect by inheriting from an interface named IRhoconnectCRUD. Add it to the class definition in AddressesController:

  public class AddressesController : Controller, IRhoconnectCRUD 

You will need to add references to the RhoConnect library:

using RhoconnectNET; using RhoconnectNET.Controllers; 

The interface requires four methods to be implemented. They provide the basic CRUD (Create, Read, Update, Destroy) functionality that our RhoConnect server will use to communicate with the app. The signatures for the methods are:

    jsonresult rhoconnect_query_objects(string partition);

    actionresult rhoconnect_create(string objjson, string partition);

    actionresult rhoconnect_update(dictionary<string, object> changes, string partition);

    actionresult rhoconnect_delete(object objid, string partition);

Note that the rhoconnect_query_objects method is what is called when RhoConnect wishes to perform a query on the database. In our case the query is quite simple: return all of the Addresses:

  public JsonResult rhoconnect_query_objects(String partition) {

    return Json(db.Addresses.ToDictionary(a => a.ID.ToString()));

  }

Notice that JSON is the primary data format that is used in the communication to RhoConnect.

In order to allow RhoConnect to update a record we implement the rhoconnect_update method:

public ActionResult rhoconnect_update(Dictionary<string, object> changes, String partition) {

    int obj_id = Convert.ToInt32(changes["id"]);

    Address address_to_update = db.Addresses.First(a => a.ID == obj_id); // this method will update only the modified fields

    RhoconnectNET.Helpers.merge_changes(address_to_update, changes);

    db.Entry(address_to_update).State = EntityState.Modified; db.SaveChanges();

    return RhoconnectNET.Helpers.serialize_result(address_to_update.ID);

}

The other methods are implemented in the sample application that is included with this post.

We also must tell the MVC app how to initiate the communication with the RhoConnect server. We do this by adding the following methods to the Global.asax.cs file:

private void init_rhoconnect() {

    // this call allows parsing JSON structures into Objects

    ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());

    RhoconnectNET.Client.set_app_endpoint("http://localhost:9292", "http://localhost:3000", "my-rhoconnect-token", rhoconnect_authenticate);

}

 

private bool rhoconnect_authenticate(ref String username, String password, Hashtable auth_attrs) {

    return true;

}

The init_rhoconnect() method sets up the end point that is used to communicate with the Rhomobile application. The call RhoConnect.Client.set_app_endpoint takes the URL of the RhoConnect app, the URL of the MVC app, a shared token that we will use for the connection, as well as a method for authentication. In our case the authentication is always returning true for this simple example.

We then add the init_rhoconnect() method call to the end of the Application_Start method in Global.asax.cs.

RhoConnect Server

Next we need to configure the actual RhoConnect server.

Open a command prompt in our root plugins directory and type:

rhoconnect app address_server cd address_server 

This will create our RhoConnect server application. The Rhoconnect server will manage the communication and synchronization between our mobile client and the .NET server application we'll develop.

Next, using your editor or choice, within the new app open the file settings/settings.yml add the adapter_url line to the development section:

:development:

    :licensefile: settings/license.key

    :redis: localhost:6379

    :syncserver: http://localhost:9292

    :push_server: http://someappname@localhost:8675/

    :api_token: my-rhoconnect-token

    :adapter_url: http://localhost:3000

The adapter_url line will point to our .NET app. In development we've set up our app to use port 3000 on localhost. This line allows our RhoConnect app to know where the data resides when synchronizing with mobile apps.

Note the api_token is set to my-rhoconnect-token. This token will be used with the .NET app to create a shared token between the apps. In a production environment you'll want to use a more secure token.

Note also that the sync server is running on localhost at port 9292. This is the URL and port of your RhoConnect server. In production this would point to the IP on the Internet where your application is installed.

Create a Rhodes App

In order to test our architecture based on the plugin we're going to create a simple Rhodes app to display and update the list of addresses. From our /plugins root directory do:

rhodes app addresses

cd addresses

Add an Address model:

rhodes model address Name,Address1,Email 

Be sure not to add spaces between the fields. This will create the files we need to support our Address model.

Edit the app/Address/address.rb to enable sync:

# The model has already been created by the framework, and extends Rhom::RhomObject

# You can add more methods here

class Address

    include Rhom::PropertyBag

    # Uncomment the following line to enable sync with Address.

    enable :sync

    #add model specific code here end

Edit the rhomobile.txt to point to the sync (RhoConnect) server:

syncserver = 'http://localhost:9292' 

Also change the start path for the app to display our list of addresses:

start_path = '/app/Address' 

And we're done!

Testing the Apps

In order to test the app's ability to talk to each other we'll launch them all in separate shell (or command) windows.

Start up the services:

Start redis:

cd address_server rhoconnect redis-start  

Open a new shell and start Rhoconnect from the same folder:

cd address_server rhoconnect start 

Start the .NET app

Using Visual Studio hit the Run button to start the project in debug mode. In production you would configure IIS to serve the application as a web site.

Start the Rhodes app in the simulator (iPhone simulator):

For our example we'll run the Rhodes app in the RhoMobile simulator instead of on an actual device. This allows us to use localhost to serve the components of our solution.

Run the simulator:

cd contacts

rake run:android:rhosimulator

Once the app starts up log in using the username "app" with no password.

Testing the synchronization

Open a web browser and navigate to the Address controller in our web app by visiting: http://localhost:3000/address

Click the "Create New" link and create a new address by entering values in the fields:

Imgur

The mobile device should show 1 entry.

Imgur

On the mobile app enter:

Imgur

You should now see 2 listings on the mobile app.

Press the sync button and return to the web app.

A view of the Address records shows the data on the .NET side at http://localhost:3000:

Imgur

That's it! Your .NET Address model is exposed to the Rhodes app for synchronization. Data will automatically be updated on both ends whenever it changes on either end.

Conclusion

RhoConnect plugins are a fast way to enable a back end to hook into the RhoMobile framework. In this example we used .NET MVC as the back end platform, but it could have been any other platform that is supported by the plugin architecture.

RhoConnect plugins allows you to use a variety of back-end solutions, whatever your legacy platform may be. This gives you great flexibility in creating mobile applications that access enterprise data.

About the Author

profile for Richard Brown at Stack Overflow, Q&A for professional and enthusiast programmers

Richard Brown is a Senior Developer and Architect at Kutir Mobility. His specialties include iOS, Ruby on Rails, and RhoMobile development.

About Us

Facing challenges with your RhoMobile implementation? Kutir Mobility, a Motorola Certified partner, can help you get your app done on time. Get in touch with us today at info@kutirtech.com , no strings attached.

This the first of three articles on how RhoConnect can be combined with various platforms such as Ruby on Rails, Java, and .NET.


The Rho platform was developed as a cross-platform solution that offers powerful tools for uniting enterprise data with mobile devices.  One key part of that strategy is the RhoConnect sync server platform.  RhoConnect offers an easy-to-implement way of keeping the data on the mobile device and your back end storage synchronized.

 

As Motorola states:

RhoConnect is the first of a new category of “mobile app integration” servers. Using RhoConnect drastically simplifies the development of connectivity to an enterprise backend app. The RhoConnect server and built-in RhoConnect client in the smartphone app perform all the work to get data down to the device. This eliminates 50 to 80 percent of the development effort in enterprise smartphone apps: performing the backend application integration.

-- http://docs.rhomobile.com/en/5.0.0/rhoconnect/introduction

 

There are several ways to interface your back end systems to RhoConnect (and indirectly your mobile devices).  It's up to you, as the developer, to choose the best method suited to your needs:

 

1. RhoConnect REST API

 

RhoConnect has a REST API that allows direct and custom services to be developed with it as the platform.  The API allows you to tie in complicated back end systems by giving you direct control of the RhoConnect service.  This means your solution can be as simple or as complicated as you wish it to be.

 

2. RhoConnect Source Adapters

 

A RhoConnect source adapter gives you a framework that encapsulates the RhoConnect API, but gives you the leeway to include your own business logic through models and controllers.  The source adapter is a good choice if you wish to have a framework to automate the actual communication with RhoConnect, yet maintain the ability to inject custom business logic into the process.

 

3. RhoConnect Plugins

 

From Motorola:

Rhoconnect Plugins allow you to connect your backend apps seamlessly with rhoconnect. You can write the source (query, create, update and delete operations) into a backend application, and use a RhoConnect plugin in the language that matchs your backend application, such as Java or .NET."

 

A Rhoconnect plugin  encapsulates the integration of your back end solution and RhoConnect in a library that handles the communication seamlessly.  You simply implement your application's models and through the plugin RhoConnect will automatically synchronize your data across your mobile devices.

RhoConnect plugin -

 

- image source Motorola: (http://docs.rhomobile.com/en/4.1.0/rhoconnect/plugin-intro)

 

In this article we're going to examine how to implement a RhoConnect plugin using Ruby on Rails as the back end application.  Ruby on Rails provides an excellent framework for rapidly developing applications that can communicate with a variety of database platforms, including MySQL, PostgreSQL, and MS SQL Server.  The RhoConnect plugin will connect our Rails application data to a Rhodes mobile application transparently.

 

To demonstrate RhoConnect plugins we're going to use three different apps:

  • A RhoConnect server
  • A Rails 4 app with the Rhoconnect-rb gem
  • A Rhodes mobile app (using the iOS simulator)

 

We're using a Mac as the development platform in this excersize but Windows is also supported.  Install the RhoMobile Suite to get the toolchain you need to follow this post.

 

For our example we're going to set up a very simple address book.  It will allow the end user to view a set of addresses, along with names and email addresses associated with those addresses.  We will be able to update this list of names from both the mobile device and the Rails back end.  Let's get started!

 

The Setup

 

We're going to emulate the Internet on our local computer, meaning our applications will all be on localhost.  In a production or staging environment your RhoConnect and Rails app will be hosted on an application server, while your Rhodes app will reside on a mobile device such as an iPhone or Android device.  Let's create a root directory and create all of our applications as subdirectories from this root.

 

mkdir plugins

cd plugins

 

The first application we're going to configure is the RhoConnect service itself.  You can install it by using the command:

 

gem install rhoconnect

 

This will install the RhoConnect service gem on our computer.  Next we need to install redis:

 

rhoconnect redis-install

rhoconnect dtach-install  <--- install this as well on a Mac

 

 

Finally we can create our RhoConnect app:

 

rhoconnect app address_server

cd address_server

 

 

In the settings/settings.yml add the :sources: section and add the adapter_url line to the development section:

 

:development:

  :licensefile: settings/license.key

  :redis: localhost:6379

  :syncserver: http://localhost:9292

  :push_server: http://someappname@localhost:8675/

  :api_token: my-rhoconnect-token

  :adapter_url: http://localhost:3000

 

The adapter_url line will point to our Rails app.  In development Rails apps by default use port 3000 on localhost.  This line allows our RhoConnect app to know where the data resides when synchronizing with mobile apps.

 

Note the api_token is set to my-rhoconnect-token.  This token will be used with the Rails app to create a shared token between the apps.  In a production environment you'll want to use a more secure token.

 

Note also that the sync server is running on localhost at port 9292.  This is the URL and port of your RhoConnect server.  In production this would point to the IP on the Internet where your application is installed.

 

Create the Ruby on Rails back end app using the RhoConnect Plugin

 

Next we'll create our Rails back end application.  Here we're using Rails 4, as it's the latest version of the framework available.  Rails 3 will also work; as a matter of fact it's the version that the plugin supports by default.

 

rails new address_book cd address_book

 

The official gem doesn't support Rails 4 yet, so I had to fork it to add support for that version of Rails.

Edit the Gemfile and add:

 

gem 'rhoconnect-rb', github: 'chronosafe/rhoconnect-rb'

 

If you're using Rails 3 instead, use:

 

gem 'rhoconnect-rb'

 

This gem is the actual plugin and provides the glue between the app and RhoConnect.  Behind the scenes it builds controllers and routes to your app to support communication with your RhoConnect app transparently.

 

Next we need to add the model for the address book:

 

rails g scaffold Address name address email

 

This creates the store for our addresses.  Note that we're using SQLite3 for our data store as it is the default for Rails and requires no configuration.

 

Run the rake task to process the migration:

 

rake db:migrate

 

This will create our database for us.

 

Next we need to add an initializer to the config/initializers directory.  This will allow us to configure our communication with RhoConnect.  Create a file in config/initializers named rhoconnect.rb and add the following:

 

Rhoconnectrb.configure do |config|

  config.uri    = "http://localhost:9292"

  config.token  = "my-rhoconnect-token"

  config.app_endpoint = "http://localhost:3000"

  config.authenticate = lambda { |credentials|

    # User.authenticate(credentials[:login], credentials[:password])

    true

  }

end

 

The config.uri line points to our RhoConnect application.  The config.app_endpoint strangely enough points back to the Rails app itself.

 

Notice the config.token line.  This token matches the token we created in our RhoConnect app.  We can create an authentication system for our application here as well.  RhoConnect will pass the user that is attempting to access the back end.  We can authenticate this user using normal Rails authentication.  I've commented this out for our simple example and just return true, meaning everyone is authenticated.

 

Next we need to make some changes to the app/models/address.rb file to add the support for RhoConnect:

 

class Address < ActiveRecord::Base

  include Rhoconnectrb::Resource

 

  # RhoConnect partition

  def partition

    :app

  end

 

  def self.rhoconnect_query(partition, options={})

    all

  end

end

 

The include statement adds the RhoConnect plugin as a module to our model's class. This module includes all the functionality to enable this model to be updated (and to update) RhoConnect through the plugin.

 

Each model that supports the plugin must also implement two functions.  The first function is named partition and allows us to uniquely identify the scope of the data to be queried.  For example, you could define the partition to be the username used by the requesting mobile app.  In our case we're simply going to use :app, which means a global scope.

 

Next we must define a class method named rhoconnect_query.  This method is used by the plugin to actually query the database for a recordset when it needs to retrieve data.  Notice you're passed in the partition to use as a scope, as well a s a hash of options that can further refine the query.  For our example we're going to return all, which means the entire list of addresses.

 

With these modifications our Rails app is ready to communicate with RhoConnect.

 

Create a Rhodes App

 

In order to test our architecture based on the plugin we're going to create a simple Rhodes app to display and update the list of addresses.  From our /plugins root directory do:

 

rhodes app addresses

cd addresses

 

Add an Address model:

 

rhodes model address name,address,email

 

Be sure not to add spaces between the fields.  This will create the files we need to support our Address model.

 

Edit the app/Address/address.rb to enable sync:


Rhom::RhomObject

# You can add more methods here

class Address

  include Rhom::PropertyBag

 

  # Uncomment the following line to enable sync with Address.

  enable :sync

 

  #add model specific code here

end


Edit the rhomobile.txt to point to the sync (RhoConnect) server:


syncserver = 'http://localhost:9292'


Also change the start path for the app to display our list of addresses:

 

start_path = '/app/Address'

 

And we're done!

 

Testing the Apps

 

In order to test the app's ability to talk to each other we'll launch them all in separate shell (or command) windows.

 

Start up the services:

 

Start redis:


cd address_server

rhoconnect redis-start


Open a new shell and start Rhoconnect from the same folder:


cd address_server

rhoconnect start


Start the Rails app in another shell window:

 

cd address_book rails server

 

Start the Rhodes app in the simulator (iPhone simulator):

 

If using the iPhone simulator you'll need to update the version in the sdk in the build.yml file (it defaults to iOS 6):

 

iphone:

  configuration: Release

  sdk: iphonesimulator7.0

 

Run the simulator:

 

cd contacts

rake run:iphone

 

Enter any username you wish and tap go to login.

 

Testing the synchronization

 

Open a new shell and go to the Rails app:

 

cd address_book rails console

 

This will open the rails console for the app.  Add a record to the database:

 

> Address.create(name: 'Abraham Lincoln', address: '1600 Pennsylvania Ave.', email: 'alincoln@whitehouse.gov')

> Address.all.count

 

The mobile device should show 1 entry.

 

Imgur

 

On the mobile app enter:

 

Name: Winston Churchill

Address: 10 Downing St.

Email: wchurhill@gov.uk

 

You should now see 2 listings on the mobile app.

 

Imgur

 

Press the sync button and return to the Rails app console:

 

> Address.all.count

 

Should now return 2.

 

A quick scaffold shows the data on the Rails side at http://localhost:3000:

 

rails data

That's it! Your Rails Address model is exposed to the Rhodes app for synchronization.  Data will automatically be updated on both ends whenever it changes on either end.

 

Conclusion

 

RhoConnect plugins are a fast way to enable a back end to hook into the RhoMobile framework.  In this example we used Ruby on Rails as the back end platform, but it could have been any other platform that is supported by the plugin architecture.

 

The next time you need to tie in a Rails app to your RhoMobile application take a look at the RhoConnect plugin system.  It could be the perfect fit for your solution.

 

Want to try it yourself?  The code from the article is available at the Github repo: richard-kutir/rhoconnect-plugin · GitHub

 

About the Author

profile for Richard Brown at Stack Overflow, Q&A for professional and enthusiast programmers

Richard Brown is a Senior Developer and Architect at Kutir Mobility.  His specialties include iOS, Ruby on Rails, and RhoMobile development.

 

About Us

 

Facing challenges with your RhoMobile implementation? Kutir Mobility, a Motorola Certified partner, can help you get your app done on time. Get in touch with us today at info@kutirtech.com , no strings attached.

What are push notifications?

 

If you are already familiar with the concept of push notifications, skip to the next section for information on how to get started using them in your own app.

 

The concept of a "push notification" is simple: instead of having your application continuously asking the server "is there anything I should know about?" ("pulling" information from the server), the server instead notifies the application when an event of interest occurs. The name "push notification" comes from the fact that the server "pushes" the message to the client instead of passively waiting for the client to initiate a connection.

 

Another advantage of push notifications is that users will receive the notification even if a particular application is not currently running: if you are developing an application for keeping track of to-dos and a manager assigns a task to an employee, the employee will receive the notification even if he is not currently working with the to-do application.

 

What devices and OSs support which push mechanism? The reason for the existence of RhoConnect Push

 

The concept of a server-initiated notification has been around for a long time in one form or another and most current mobile operating systems offer their own facilities for handling notifications. The differences between platforms are significant, with some platforms supporting several alternatives and others not providing any out of the box:

 

iOS offers its own Apple Push Notification Service and disallows the use of any other push service.

 

Android devices with the Google Play Store (most consumer-oriented devices fall in this category) include Google Cloud Messaging (GCM) , "a free service that helps developers send data from servers to their Android applications on Android devices, and upstream messages from the user's device back to the cloud".

 

Android devices from OEMs like Motorola Solutions may not include the Google Play Store or more holistically - Google Mobile Services or GMS for short. Google Cloud Messaging requires these services in order for it to work, which means most enterprise-oriented devices like the ET1, MC40 and most versions of the TC55 do not provide native push capabilities. The reason for this omission is that most enterprises do not want to be bound by Google's Terms of Service for one reason or another and the unfortunate consequence is that developers need to implement their own push solution. RhoConnect Push Service is the logical alternative to Google Cloud Messaging in this case.

 

Windows Mobile does not provide any native push notification capabilities and, again, RhoConnect Push Service saves the day.

 

RhoConnect Push Service was born out of the necessity to provide push notifications on every platform, irrespective of their native capabilities. In a nutshell, RhoConnect Push Service is a seamless way for your application to receive push notifications where the native platform falls short. It is available on Android (both on devices with the Play Store and on those without it like the TC55 and MC40) as well as on Windows Mobile.

 

Here are your options for using push notifications today:

 

PlatformNativeRhoConnect PUSH
iOSYESNO
Android devices with GCM (consumer)YESYES
Android devices without GCM (enterprise)NOYES
Windows MobileNOYES

 

As you can see, on iOS the choice is clear: you have no option but to use Apple's APNS service. Windows Mobile does not leave much to the imagination either: since it has no native notification capabilities, you have to either implement them yourself or use RhoConnect Push Service.

 

The waters are slightly murkier on Android: some devices (mostly consumer-oriented) support Google's notification service, but most enterprise devices like the MC40 and TC55 do not. Furthermore, in the case of the TC55, there are versions of the device with Google's services and versions without them. However, you do not want to maintain two separate code bases or unnecessarily limit your app to only one particular version or device, plus you may be required to support different devices in the future.

 

RhoConnect Push Service was developed to solve this exact problem, freeing you from the differences in notification capabilities across devices and helping you bring your application to market more quickly. Enterprise mobile applications that need push notifications should use RhoConnect Push Service if they are targeting enterprise-grade devices, as this provides the most flexibility for deployment on all types of devices. In the next section you will learn how to integrate RhoConnect Push Service on an application designed for the MC40 or TC55 and the exact same steps and code can be used for deployment on any other Android device.

 

 

RhoConnect Push walkthrough. From nothing to push-enabled app in 10 minutes.

 

Once you have decided to give RhoConnect Push Service a try, you will find that setup and implementation are surprisingly straightforward, with just a handful of steps to complete and very little code required on your part.

 

Installing Rhoconnect and RhoConnect Push Service.

 

Refer to the official documentation on RhoConnect Push Service. In short, you need to complete two steps:

  • Install RhoConnect and RhoConnect Push Service on your server (for the purpose of this tutorial, install them on your local machine). While following the instructions, you will reach a point where you have to edit the settings/settings.yml file and assign the push_server. Instead of "someappname", use "rhoconnectpushtest" as shown below and make a mental note to remember this value, as you will use it again shortly on your mobile client:

 

 

    :push_server: http://rhoconnectpushtest@localhost:8675/







 

 

  • Install RhoConnect Push Client on your TC55, MC40 or other mobile device. Again, refer to the RhoConnect Push Service documentation where you will find step-by-step instructions of where to find the files you need to install and how to install them.

 

 

    Once the services are configured, start them:

  • start rhoconnect with
    rake redis:start
    rhoconnect start







 

  • start rhoconnect push with
    rhoconnect-push







 

 

Configuring your app to handle push notifications

 

Now that the server is ready, let's build a client to go with it. Start by creating a new RhoMobile app with

 

rhodes app pushtest







 

 

then edit rhoconfig.txt and configure the following values, making sure to substitute 192.168.1.2 with the IP address of your computer.

 

syncserver = 'http://192.168.1.2:9292'
Push.rhoconnect.pushServer = 'http://192.168.1.2:8675'
Push.rhoconnect.pushAppName = 'rhoconnectpushtest'







 

The pushAppName parameter must match the one we configured above in "push_server". In a production environment, please use a different value and treat it as a sort of authentication token that should not be disclosed publicly.

 

Edit app/application.rb and add the following code at the end of the "initialize" method:

 

Rho::Push.startNotifications '/app/Settings/push_callback'







 

This tells RhoMobile which action to invoke when a push notification is received.

 

Now edit app/Settings/controller.rb and add the following code:

 

def push_callback
  Rho::Notification.showPopup({'message' => @params['alert'], 'buttons' =>['OK']})
end







 

This is the code that will receive the notification. For now, we will just show a popup, but your application can do anything you need. A common use case is to use a push notification as a trigger for the app to synchronize data with RhoConnect.

 

 

Testing notifications

 

Now that all the pieces are in place, it's time to see notifications in action! Please note that you will need to install your application on an actual device, you will not be able to test notifications on RhoSimulator. Start your app on a mobile device and log in with any username and password. The easiest way to test notifications is from within RhoConnect's own admin console. Point your browser to http://localhost:9292/console , click "login" and go to the "Users" tab. Click the "Ping users" button, edit the message and click "Ping!". Now look at your mobile device and you should see a popup message, just as you would expect from the code in the "push_callback" method.

 

What's next

 

Testing notifications manually is fine during the initial stages of development. Once you move past that point, you may be interested in looking at the RhoConnect REST API, which allows you to send notifications programmatically. Additionally, in a future post we will cover how to use RhoConnect Push Service in a native Android (non-rhodes) application. If you want to handle these push notifications in a native Android application, you can write a very trivial RhoMobile application that simply is configured to receive the RhoConnect Push notification, as previously mentioned, and then trigger an Android intent using the Rho.Intent API. Now whether you are writing RhoMobile applications or Native Android applications, you will be able to receive Push Notifications.

 

About us

 

Facing challenges with your RhoMobile implementation? Kutir Technologies, a Motorola Certified partner, can help you get your app done on time. Get in touch with us today at info@kutirtech.com , no strings attached.

Continuing with our exploration of the Javascript MVC landscape, today is the turn of Ember.js. "A framework for creating ambitious web applications" is how it describes itself on its home page, read on to find out if there is any merit to that claim.

 

A word of warning

 

At the time of this writing, the production version of ember.js contains 995 KB of javascript code (238 KB minified) which is clearly not what you would call lightweight and, in fact, may be too much for certain devices to load over the network. If you have to support Windows Mobile devices, be sure to test on real hardware before you commit to using Ember.js for an application. Including the .js file in a native RhoMobile 4 application tends to work well with the RhoElements webkit, but loading it on demand from a server can be problematic.

 

Basic concepts

 

  • Ember.js is a very opinionated framework: it dictates a structure for your code and you are expected to follow it, not fight it.
  • Your application will be structured around the concept of the URL: The URL you are currently in represents the state of the application and is the entry point.
  • Once you browse to a particular URL
    • the Router parses it and decides which Route to activate
    • the Route loads the appropriate Model for the View
    • the View renders its Template
    • the Controller handles actions that the user performs in the View
  • The name of each part of your application must follow the Ember.js naming convention: for the URL "/about", you will have App.AboutRoute and App.AboutController as well as an "about" template.

 

 

With that knowledge on hand, let's learn the absolute minimum that will let us start having fun.

 

 

Views / Templates

 

Ember.js by default uses the Handlebars templating library, which lets you create two-way bindings between your views and their underlying model. Whenever your model changes, the view is updated automatically without you having to write or manage any code. Here is an example:

 

<p>{{input type="text" value=username}}</p>
<p>Hello, {{username}}</p>



 

As you type in the input field, the greeting will update itself.

 

When you start building real applications, you will have different views and each view will have its own template. The easiest way to get started is by keeping your templates in <script> tags:

 

<script type="text/x-handlebars" id="welcome">
  Hello, {{username}}!
</script>

<script type="text/x-handlebars" id="goodbye">
  Goodbye, {{username}}
</script>



 

The type attribute tells the browser that this is not javascript, so it should not try to execute what is inside the tag, and the id is what will link a particular template with its corresponding route. By default, Ember.js looks for a script without a name (the application template) and uses it as a decoration for the rest of the views:

 

<script type="text/x-handlebars">
  <div id="header">
  Welcome to the Ember.js demo application
  </div>
  <div id="content">
  {{outlet}}
  </div>
</script>



 

See that {{outlet}} ? That's where the current view will be rendered.

 

Apart from using {{ }} to create bindings between the user interface and your model, there are other interesting features in handlebars:

 

Conditionals

 

{{#if condition}}
  Condition is true
{{else}}
  Condition is false
{{/if}}



 

Iteration

 

{{#each currentProduct in products}}
  {{currentProduct.name}}
{{/each}}



 

Tag attribute bindings

 

<img {{bind-attr src=userImage}}>



 

Creating links to routes

 

{{#link-to "product.detail" currentProduct}} Details for product {{currentProduct.name}} {{/link-to}}



 

Actions

 

<button {{action 'buyProduct'}}>Buy this product</button>



 

The above will link the <button> tag in the view to the "buyProduct" action in the controller. We will talk about controllers later in this article.

 

Routing

 

We mentioned earlier that Ember.js considers the URL as the center of your application and will parse it to figure out which part of the application should be activated. A side effect of that is that you must tell Ember.js which URLs your application will react to; there are two concepts that the Router in Ember.js knows about: routes and resources.

 

A route is just what you would expect: you tell the router that the application knows about a particular URL and Ember.js takes care of the rest. Creating a top-level route is straightforward:

 

App.Router.map(function() {
  this.route("welcome");
});



 

This creates a route named "welcome" that will load a template with the same name and be handled by App.WelcomeRoute and App.WelcomeController whenever you visit /welcome. If you do not define WelcomeRoute or WelcomeController in your code, Ember.js will generate them for you automatically, so you can create routes with simple views very easily.

 

The other construct is what Ember.js calls a "resource", which is nothing more than a route that can have sub-routes. Let's say we want to have a "/product" route that shows a list of products and we also want to show the details of a particular product at "/product/1234".

 

App.Router.map(function() {
  this.resource("product", function() {
  this.route("details", {path: "/:product_id"});
  });
});



 

That code creates two routes, named "product" and "product.details" and Ember.js expects to find them as ProductRoute and ProductDetailRoute:

 

App.products = ["product 1", "product 2"];

App.ProductRoute = Ember.Route.extend({
  model: function() {
  return App.products;
  }
});

App.ProductDetailRoute = Ember.Route.extend({
  model: function(params) {
  return App.products[params.product_id];
  }
});



 

The relationship between a resource and its routes is deeper than merely one being contained in the other in the URL: it is expected that the template of the parent route will contain an {{outlet}} so that the child route is rendered within it. That makes it very easy to build master-detail pages of arbitrary depth and reflects the hierarchical nature of the URL:

 

<script type="text/x-handlebars" id="product">
  <div id="productlist">
  {{#each product}}
  Product {{product}}
  {{/each}}
  </div>


  <div id="productdetails">
  {{outlet}}
  </div>
</script>


<script type="text/x-handlebars" id="product/details">
  Details for product {{this}}:
  - foo
  - bar
  - baz
</script>



 

Controllers

 

Controllers are where you you write the code that deals with actions from the user:

 

App.ProductDetailController = Ember.Controller.extend({
  actions: {
      buyProduct: function() {
            alert('You have bought the product. Enjoy!');
      }
  }
});



 

Think of controllers as decorators for your model that add view-related functionality.

 

 

Models

 

 

Models are where you store data that must persist across application runs. Any javascript object can be an Ember.js model, although you will typically extend from Ember.Object or, if you are using Ember-Data, from Ember.Model:

 

App.Product = Ember.Object.extend({
  name: null,
  sku: null
});


App.ProductRoute = Ember.Route.extend({
  model: function() {
      return [
            App.Product.create({
            name: "Product 1",
            sku: "11111"
      }),
      App.Product.create({
            name: "Product 2",
            sku: "22222"
      })
      ];
  }
});



 

 

With those concepts in place, you are ready to see the code for a very simple warehouse application that lets you

 

  • see which products are available
  • create new products
  • delete products

 

in approximately 65 lines of Javascript code.

 

  • Create a new RhoMobile 4 application
  • Download ember.js and handlebars-1.0.0.js and put them into /public/js
  • Edit rhoconfig.txt and set start_path = '/public/index.html'
  • Create /public/index.html with the following code:

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
    <title>Sample</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
        <script src="/public/api/rhoapi-modules.js" type="text/javascript"></script>
        <script src="/public/jquery/jquery-1.9.1.min.js" type="text/javascript"></script>
        <script src="/public/js/handlebars-1.0.0.js" type="text/javascript"></script>
        <script src="/public/js/ember.js" type="text/javascript"></script>
        <script src="/public/js/application.js" type="text/javascript"></script>
</head>
<body>
    <script type="text/x-handlebars">
    {{outlet}}
    </script>

    <script type="text/x-handlebars" id="product">
        Product list
        <button {{action "addProduct"}}>Add product</button>

        <ul>
            {{#each product in controller}}
            <li>{{#link-to "edit" product}}{{product.name}}{{/link-to}}</li>
            {{/each}}
        </ul>

    {{outlet}}
    </script>

    <script type="text/x-handlebars" id="edit">
        <p>{{input type="text" value=name}}</p>
        <p>{{input type="text" value=sku}}</p>
        <button {{action "done"}}>Done</button>
        <button {{action "deleteProduct"}}>Delete</button>
    </script>

</body>
</html>



 

Even if this is your first contact with Ember.js, you will no doubt find the code above to be very self-explanatory

 

  • Create /public/js/application.js with the following code:

 

App = Ember.Application.create();

// Define which routes our application knows about
App.Router.map(function() {
  this.route("product", {path: "/"});
  this.route("edit", {path: "edit/:product_id"});
});

// This is the Product model object in our application.
// It is not necessary to specify the properties here, but making them
// explicit makes the code easier to read and reference
App.Product = Ember.Object.extend({
  id: null,
  name: null,
  sku: null
});

// This application stores data in memory only (no server and no database)
// Here is where we keep track of everything
App.appdata = Ember.Object.create({
  lastId: 0,
  products: []
});

App.ProductRoute = Ember.Route.extend({
  model: function() {
  return App.get("appdata.products");
  }
});

App.ProductController = Ember.ArrayController.extend({
  actions: {
      addProduct: function() {
            var nextId = App.appdata.incrementProperty("lastId");

            var newProduct = App.Product.create({
                id: nextId,
                name: "Product "+nextId,
                sku: "1111"+nextId
            });

            App.appdata.products.pushObject(newProduct);
            this.transitionToRoute("edit", newProduct);
    }
  }
});

App.EditRoute = Ember.Route.extend({
  model: function(params) {
      return App.appdata.products.findBy("id", parseInt(params.product_id,10));
  }
});


App.EditController = Ember.ObjectController.extend({
  actions: {
      done: function() {
            this.transitionToRoute("product");
      },
      deleteProduct: function() {
            App.appdata.set("products", App.appdata.products.without(this.get("model")));
            this.transitionToRoute("product");
      }
  }
});



 

Again, even if you are not yet familiar with how Ember.js works, this code is very simple.

 

That's it. Now run your application and you will see that, for the small amount of code we have written, we get a very featureful and very structured application that is easy to extend with new routes and views. Note in particular the complete absence of any code to update HTML elements, everything is taken care of automatically. Note also that there is no "save" button, and the "done" action in EditController is merely a redirect: changes in the view are also being applied automatically to the model. You can see these changes in real time by updating the "edit" template as follows:

 

    <script type="text/x-handlebars" id="edit">
        <p>{{input type="text" value=name}}</p>
        <p>{{input type="text" value=sku}}</p>
        <button {{action "done"}}>Done</button>
        <button {{action "deleteProduct"}}>Delete</button>
        <p>{{name}}</p>
        <p>{{sku}}</p>
    </script>



 

If you run the application now, you will see that as soon as you change the contents of the input field, the values below are updated in real time.

 

The model in this application, however, is not being saved to persistent storage, which means that the next time you open the application, the data will be gone. In a real application, you will want to store your data either in a server (possibly via AJAX calls) or with Rhom (or even both with Rhom and a server with RhoConnect). Ember.js has an optional library called Ember Data that helps you treat different data sources with a single, common API. If your server provides a JSON REST API, Ember Data's RestAdapter will help you connect your mobile app and if you want to take advantage of on-device storage with Rhom, there is a rhomobile-ember sample where you can see a more advanced version of this application together with a Rhom adapter for Ember Data. See this link to know how to enable it.

 

There is a lot more to Ember.js than what we can cover here and once you have gone through this tutorial, you will want to browse through the official guides, which are an excellent source of information.

 

Speak up!

Did you find this post useful? What else would you like to see covered? Leave a comment below, we read all messages and try to accomodate requests whenever possible.

In the previous post of this series we revealed that RhoConnect source adapters can now be written in Javascript, which lets you use the same language to write both the client (RhoMobile apps) and the server side (RhoConnect source adapters) of an enterprise application and we also saw, at a high level, how these adapters are built. Today we are going to take a deep dive and see how to actually write one.

 

First things first. What are we going to build?

 

We already have a sample Javascript CRUD application created 100% in Javascript, you can see how it was built at http://edgedocs.rhomobile.com/guide/rhom_backbone. We will take this application (available for download https://github.com/javiermolina1234/rhomobile-backbonejs-sample ), develop the corresponding RhoConnect server and enable synchronization between the two.

 

Prerequisites:

 

In order to follow this tutorial, you need to have already installed on your machine:

 

  • RhoMobile 4.0 and its own prerequisites like an appropriate version of Ruby. Do not worry if you have not used Ruby before, though, as you will not need to touch it at all. You can consider it as a dependency you do not have to interact with.
  • Redis
  • Node.js
  • SQLite3 installed and present in the PATH environment variable

 

 

Additionally, you will want to get a copy of the client application by either cloning https://github.com/javiermolina1234/rhomobile-backbonejs-sample or by downloading https://github.com/javiermolina1234/rhomobile-backbonejs-sample/archive/master.zip

 

Next, open a terminal / system prompt and use the rhoconnect command to create a new RhoConnect application:

 

rhoconnect app js-example --js

 

That will create a barebones rhoconnect application. Note the --js flag at the end: it tells the rhoconnect command that we intend to use Javascript and it will cause the newly-generated application to be ready for Javascript source adapters. Because the client application you downloaded has a model called "Product", we will add a source adapter with that same name:

 

cd js-example
rhoconnect source Product --js

 

Again, the --js flag is a signal to the rhoconnect command that we wish to generate a Javascript (not Ruby) source adapter. With those preliminary steps out of the way, we can now roll up our sleevs and get our hands dirty writing some code. Open models/js/product.js (which we just created) and have a look at it:

 

var rc = require('rhoconnect_helpers');

var Product = function(){

  this.login = function(resp){
    // TODO: Login to your data source here if necessary
    resp.send(true);
  };

  this.query = function(resp){
    var result = {};
    // TODO: Query your backend data source and assign the records
    // to a nested hash structure. Then return your result.
    // For example:
    //
    // {
    //   "1": {"name": "Acme", "industry": "Electronics"},
    //   "2": {"name": "Best", "industry": "Software"}
    // }
    resp.send(result);
  };

  this.create = function(resp){
    // TODO: Create a new record in your backend data source.  Then
    // return the result.
    resp.send('someId');
  };

  this.update = function(resp){
    // TODO: Update an existing record in your backend data source.
    // Then return the result.
    resp.send(true);
  };

  this.del = function(resp){
    // TODO: Delete an existing record in your backend data source
    // if applicable.  Be sure to have a hash key and value for
    // "object" and return the result.
    resp.send(true);
  };

  this.logoff = function(resp){
    // TODO: Logout from the data source if necessary.
    resp.send(true);
  };

  this.storeBlob = function(resp){
    // TODO: Handle post requests for blobs here.
    // Reference the blob object's path with resp.params.path.
    new rc.Exception(
      resp, "Please provide some code to handle blobs if you are using them."
    );
  };
};

module.exports = new Product();

 

As you can see, it's just a simple Node.js module that contains a few functions with predefined names. "login" and "logoff" let you establish and tear down connections to your backend data source if required, but "query", "create", "update" and "del" are where the rubber meets the road: these are where you will access your backend and return data to your mobile app.

 

To keep things simple in this tutorial, we will use an embedded SQLite database but you will see that the principles are the same whether your data is stored on a MySQL, MSSQL Server or Oracle database. We will tell Node.js that our code uses sqlite by opening package.json and adding the "dblite" module to the dependencies:

 

{
  "name" : "rhoconnect",
  "version" :"1.0.0",
  "main": "rhoconnect",
  "dependencies": {
    "redis" : "*",
    "dblite": "*"
  }
}

 

Run npm install so that the dblite module is added to your RhoConnect app.

 

npm install

 

 

That makes the dblite module available to our code, but we still have to reference it. Open model/js/products.js and add the relevant line as shown below:

 

var rc = require('rhoconnect_helpers');
// add the following line in your product.js file
var dblite = require('dblite');

 

That gives us access to the system's installed sqlite instance and this is why you need to have sqlite installed on your machine for this example, the dblite module invokes sqlite3 under the hood and pipes commands and results to and from the sqlite3 process.

 

Next, add some initialization code:

 

var Product = function(){

  // use a database in the root folder of our project
  var db = dblite(__dirname+'/../../database.db');

  // create a table to store products if we have not done so yet
  db.query('create table if not exists Products (id integer primary key, name text, brand text)');


 

 

We will open a database called "database.db" two levels up from our product.js file, which corresponds with the top-level folder of this RhoConnect instance, and create a table to store our product data. If the table is there already from a previous run, the "if not exists" clause will save us from causing an error.

 

Until now, we have been doing mostly preparation work; now is where it gets real: the query method.

 

query

 

As we saw in the previous installment of this two-part series, "query" corresponds to the Read operation (get data out of the database and return it to the mobile application). Here is what our implementation looks like in this sample:

 

this.query = function(resp){
    // fetch all rows from the Products table
    db.query("select * from Products", {id: Number, name:String, brand: String}, function(rows) {

      var result = {};
      // iterate over the rows
      for (var i=0; i<rows.length; i++) {
        var row = rows[i];
        // our result value must be a hash of hashes with the structure
        // identifier : { "property" : "value" }
        result[row.id] = {"name" : row.name, "brand": row.brand};
      }

      // return the result to the mobile app
      resp.send(result);     
    });
};

 

That was not so hard after all, right? query the database to get every known product and return them in the appropriate format.

 

create

 

Apart from reading existing data, we will need some way to create new records. That's what "create" is for:

 

this.create = function(resp){
    // create the product in our database
    db.query("insert into Products values (:id, :name, :brand)",
      {
        id: null, // sqlite will populate this value automatically

        // for the rest, we use what we received from the mobile app,
        // or null if we didn't get anything for that property
        name: resp.params.create_object.name || null,
        brand: resp.params.create_object.brand || null
      });

    // send back the new product's primary key
    db.lastRowID("Products", function(lastRowID) {
      resp.send(lastRowID); 
    });
};

 

 

Again, pretty straightforward - do an insert with the appropriate values and return the primary key of the new row.

 

Once an application can create and read data, the next natural step is to be able to modify that information. Changes can take two forms: updates to existing data and deletions.

 

update

 

this.update = function(resp){
    var query = "update Products set ";
    var values = {};

    var known_fields = ["name", "brand"];

    var should_prepend_comma = false;

    for (var i=0; i<known_fields.length; i++) {
      var field = known_fields[i];
      var value = resp.params.update_object[field];
      if (typeof(value)!=="undefined") {
        if (should_prepend_comma) {
          query+=", ";
        } else {
          // we will need it next time
          should_prepend_comma = true;
        }
        query+=field+"=:"+field;
        values[field]=resp.params.update_object[field];
      }
    }
    query+=" where id=:id";
    values.id = resp.params.update_object.id;
    db.query(query, values);
    resp.send(true);
};

 

The code for update may look complex at first sight but, at the core, what it is doing is very simple. The resp.params.update_object hash contains one entry for each property that was modified in the application. The code checks to see which of "name" and "brand" are present and builds the SQL update statement dynamically. Finally, a "where" clause is added and off the query goes to the database.

 

del

 

By this point you have a very good idea of how the code for "del" is going to look like:

 

this.del = function(resp){
  db.query("delete from Products where id=:id",
    {
      id: resp.params.delete_object.id
    });
  resp.send(true);
};

 

That's it for the server side! Wasn't that a walk in the park?. Start your rhoconnect server with

 

rhoconnect start

 

and on to the client side - the RhoMobile app.

 

The client side

 

The app you downloaded is completely functional but it only stores data locally. What you have to do to link it to your shiny new RhoConnect server is:

 

- open rhoconfig.txt and set syncserver to the IP address of the computer where you are running RhoConnect. For this example, you can just set it to localhost and run the app on RhoSimulator on the same computer:

 

syncserver = 'http://localhost:9292'

 

- open public/js/application.js and look for comments about RhoConnect. There are two things to uncomment in this file, one is a call to login near the top:

 

Rho.RhoConnectClient.login('user1', 'password');

 

and the other is near the end of the file

 

// Uncomment for RhoConnect integration

$(document).on("click",".sync", function() {
  Rho.RhoConnectClient.doSync();
});

 

- in build.yml, uncomment the rhoconnect-client extension

 

- finally, open public/_templates.html and you will find another thing to uncomment: a button to trigger synchronization:

 

            <button class="sync">Sync</button>

 

When you are ready, start the app with

 

rake run:rhosimulator

 

Voila, the application now boasts two way data synchronization, with Javascript being the only language you have used throughout the whole process. Try creating a few products and click "sync" so that they are sent to the RhoConnect server. Then close the app and delete the rhosimulator folder, this will erase the local database of the application. Start the app again and click sync, and it will bring back the data from the server. Refresh the page to see the results and enjoy mobile app development in Javascript.

By now, if you have followed the Launchpad forums or blogs at all, you already know that Javascript has received a lot of attention in RhoMobile Suite 4.0 and with full access to every API at the same level as Ruby, writing enterprise mobile apps completely in Javascript is now possible.

 

If that was not good enough, RhoMobile 4 has another pleasant surprise for you: RhoConnect, the server that handles two-way synchronization between a RhoMobile app and an enteprise data store, can now be programmed in Javascript too. Javascript programmers of the world, rejoice in the knowledge that your favorite language can now take you all the way from the client to the server and back. Using only Javascript, you can now write the server-side part of a RhoMobile application too, thanks to the new built-in RhoConnect-Node.js integration.

 

Getting started with Javascript in RhoConnect

 

Assuming you have installed RhoMobile Suite 4.0 and Node.js already, the first step to start working with RhoConnect and Javascript together is to generate a new Javascript-enabled RhoConnect application:

 

rhoconnect app testserver --js

 

next, add your first source adapter: Product

 

cd testserver
rhoconnect source Product --js

 

That command will create models/js/product.js with code similar to the following:

 

var rc = require('rhoconnect_helpers');

var Product = function(){

  this.login = function(resp){
    // TODO: Login to your data source here if necessary
    resp.send(true);
  };


  this.query = function(resp){
    var result = {};
    // TODO: Query your backend data source and assign the records
    // to a nested hash structure. Then return your result.
    // For example:
    //
    // {
    //   "1": {"name": "Acme", "industry": "Electronics"},
    //   "2": {"name": "Best", "industry": "Software"}
    // }
    resp.send(result);
  };

  this.create = function(resp){
    // TODO: Create a new record in your backend data source.  Then
    // return the result.
    resp.send('someId');
  };

  this.update = function(resp){
    // TODO: Update an existing record in your backend data source.
    // Then return the result.
    resp.send(true);
  };

  this.del = function(resp){
    // TODO: Delete an existing record in your backend data source
    // if applicable.  Be sure to have a hash key and value for
    // "object" and return the result.
    resp.send(true);
  };

  this.logoff = function(resp){
    // TODO: Logout from the data source if necessary.
    resp.send(true);
  };

  this.storeBlob = function(resp){
    // TODO: Handle post requests for blobs here.
    // Reference the blob object's path with resp.params.path.
    new rc.Exception(
      resp, "Please provide some code to handle blobs if you are using them."
    );
  };
};

module.exports = new Product();

 

If you have ever developed RhoConnect source adapters in Ruby, you will immediately recognize the structure and methods there. If this is your first time, fear not: writing RhoConnect source adapters is one of the most rewarding coding activities you can find in terms of the results you get for the small effort required and the rest of this article will walk you through the process and, in the second part of this series, we will actually build one from scratch.

 

A RhoConnect source adapter does two things:

 

- connect to a backend data source (SQL, flat file, REST API, anything) and return data to a mobile application

- receive data from a mobile application and upload it to the backend

 

It is the bridge that connects your RhoConnect server (and hence your RhoMobile app) to any existing data source.

 

The RhoConnect server does most of the heavy work for you and your task is reduced to just implementing the methods in the adapter:

 

query

 

The query method is equivalent to the "select" operation in a database. It is called to fetch data from the backend and return it to a RhoMobile app. The value you return must be a hash, with keys representing identifiers and the values being another hash representing an object. Let that sink in for a second and see the following example:

 

  this.query = function(resp){
    var result = {
      "1": {"name": "ET1", brand: "Motorola", "sku": "12345"},
      "2": {"name": "iPhone 5C", brand: "Apple", "sku": "67890"}
    }
    resp.send(result);
  };

 

As you can see, this very simple adapter will return two hardcoded products. There is no need for the keys to be numbers and in fact, they are actually strings and not numbers (note the quotes). The following example using GUIDs will have the same result:

 

  this.query = function(resp){
    var result = {
      "6e13b279-182d-4922-ace0-6672cd4dd63d": {"name": "ET1", brand: "Motorola", "sku": "12345"},
      "14014408-fcce-48a8-8171-c6bd321e7d7b": {"name": "iPhone 5C", brand: "Apple", "sku": "67890"}
    }
    resp.send(result);
  };

 

These identifiers become the link between objects on a RhoMobile application and the RhoConnect server.

 

create

 

When a RhoMobile application creates a new object, it will be initially stored in the local database of the device. Once a synchronization takes place, the create method in the javascript source adapter will be called for you to insert the data into the backend as necessary. The data for the new object you are expected to create is in a hash called resp.params.create_object.

 

Similarly to "query", you must send as a return the identifier of the item that was just created but this time just a string value. There is no hash to be returned, since create only deals with one object at a time.

 

update

 

Once a RhoMobile application can synchronize data with a RhoConnect server, you will usually want to make changes to that data and send updates back to the server. The update method does just that: receive changes from the mobile app and apply them to the backend.

 

The data for the new object you are expected to create is in a hash called resp.params.update_object. That hash will not contain every property of the object, just those that were changed in the mobile app.

 

del

 

As its name implies, del (shorthand for delete) is the method in charge of deleting objects from the backend when they are deleted in a mobile app.

 

Apart from those CRUD methods, there is also login and logoff, which are called at the beginning and end of the synchronization process, and allow you to, for example, establish a database connection.

 

As you can see, following this very simple structure you can start adding two-way synchronization capabilities to your application in no time.

 

Now is a great time to start experimenting with Javascript source adapters, in anticipation of the public RhoMobile 4 release. See you in part 2 of this series, where we will build a complete source adapter from scratch completely in Javascript and see how to interact with a database.

Introduction

 

Almost every developer who has worked with server-side applications, whether in Ruby, Java, C#, PHP, Python or any other modern language, has already experienced the MVC paradigm to some extent. Even if you started your coding adventures mixing PHP together with HTML, the natural progression is to migrate to a more structured approach, separating concerns between the different parts of the application. In case you are not familiar yet with the term, MVC stands for Model-View-Controller and, in a nutshell, means that the code that handles the user interface (the view) is not mixed with code to access the database (model); instead, these are separated into distinct units, with a "controller" that links them via a well-defined interface. Have a look at the Wikipedia entry for more in-depth information. This results in applications that are easier to maintain and extend (and more fun to write).

 

 

What is Javascript MVC and why you should care

 

Javascript code, in general, did not enjoy the same amount of attention to these best practices for a long time. While there is a plethora of frameworks to choose from in other languages, it is only recently that robust Javascript MVC frameworks have appeared which bring some much-needed structure to browser applications. This "Javascript Renaissance" coincides, and not by accident, with the need to bring more and more functionality to the client (browser) side of applications, first with AJAX and with increasing frequency, with entire, complex applications being written in Javascript that operate entirely in the browser and use the server merely as a data source.

 

Javascript MVC frameworks are, in simple terms, code libraries that help you build applications in a more structured way. Additionally, some frameworks also provide utilities to work with REST APIs, templating and other functionality.

 

The main reason to adopt an MVC framework is that non-trivial applications in Javascript get more cumbersome to write as they grow and a framework will help you keep the different pieces manageable. Adding more features to your application should not become exponentially hard over time, a framework will help with that.

 

One reason to take Javascript MVC seriously is that, with the introduction of RhoMobile 4, it is now possible to access every feature directly from Javascript, no Ruby involved. Scanning barcodes? check. Database access? check. Network communication? check. Awesomeness? double check.

 

 

The Javascript MVC landscape

 

 

If in the past there was not much in the way of Javascript MVC frameworks to choose from, the problem today is exactly the opposite: the number of options has exploded into an unbelievable variety, each offering a different flavor and opinion on how applications should be built. It is out of the scope of a single article to evaluate all or even a majority of them (it would take a whole book to do so, and it would be outdated before it was published). Fortunately, there is a fantastic resource at http://todomvc.com/ where you can see one application (a to-do list) developed in multiple frameworks so that you can get a feel for the style and idioms of each. By looking at how each framework is used in a real, if small, application, you can make an informed decision about which one(s) to evaluate in more depth and eventually adopt.

 

Backbone.js

 

Backbone.js is a favorite framework for single-page applications due to its ease of use. It provides a set of conventions and building blocks to base your application on, but does not dictate the use of any particular library for building HTML views. You are free to use the included Underscore.js templating functions, mustache, handlebars or any other templating library. Once you start to develop your first Backbone.js application, you will quickly appreciate the difference between using a structured approach and the free-for-all spaghetti code that can result in plain jQuery applications once they reach a certain size.

 

There are only a few concepts Backbone.js that you must learn about in order to start being productive:

 

  • Models
  • Views
  • Router

 

Models

 

Put simply, models hold data. You create one model class per entity in your application (Product, Customer, etc) and then get and set properties on instances of that class.

 

Example:

 

var Product = Backbone.Model.extend({
  defaults: {
  sku: '',
  available: true
  },


  toggleAvailability: function() {
  this.set("available", !this.get("available"));
  }
});

 

Views

 

Views are used to render HTML. Instead of building your HTML by concatenating strings in code, a templating library will help you create HTML with a readable syntax that facilitates maintenance and change. Backbone.js does not force you to use any particular templating library, and if you do not have any preference yet, have a look at the included Underscore.js templating functions. They are very easy to get started with and will be just enough for many applications.

 

The easiest way to keep your templates manageable is to have them in an HTML file instead of a Javascript string, as that frees you from the burden of quoting, escaping special characters, etc. You can embed a template inside a <script> tag as long as you set the type attribute so that the browser does not attempt to run it as Javascript code:

 

<script id="productlist_template" type="text/template">
    <ul>
        <% _.each(products, function(product) { %>
            <li><%- product.get("sku") %> | <%- product.get("sku") %></li>
        <% }); %>
    </ul>
</script>

 

Later, in your Javascript code you can reference the template by ID and get its contents with .html():

 

var ProductListView = Backbone.View.extend({
  // this is the element on the page that this view will live in
    el: "#content",
    events: {
    //  'event    selector'       : 'method'
        'click button.create_product' : 'create_product'
    },
    initialize: function() {
        // compile template into a function and store it for future use
        this.template = _.template($("#productlist_template").html());
    },
    render: function(products) {
        // call the template to render a list of products
        var template_contents = this.template({ products : products || [] });
        $(this.el).html(template_contents); // write the template to our assigned element
    },
    create_product: function() {
    // create a product here
    }
});

 

Router

 

The router is in charge of mapping changes in the URL to actions in your code and, generally, rendering a different view. Whenever the fragment (the part after the #) changes, the router will fire an event that you can listen and react to as required.

 

 

var Router = Backbone.Router.extend({
    routes: {
        // fragment : 'method'
        ''          : 'home',
        'new'       : 'editProduct',
        // routes can also automatically interpret parts of the URL as parameters
        'edit/:id'  : 'editProduct'
    },
});

var router = new Router();


router.on("route:home", function() {
    // render home view
});

router.on("route:editProduct", function(productId) {
    // render "edit product" view, possibly with a particular productId
});

// Start listening to changes in the URL
Backbone.history.start();

 

RhoMobile 4 and Backbone.js - a match made in heaven

 

That is all you need to start building MVC applications in Javascript with Backbone.js, although there are of course some features we have not covered here. Now that you have gotten a taste of it, you can see a more comprehensive example on how to build a small CRUD application, including database access with Rhom. Backbone.js is officially supported in RhoMobile 4 and there is an integration library called RhoTendon (also discussed in the example) that helps you link Backbone.js models with Rhom for ultra-rapid development. Add to the mix the new unified access to all RhoMobile APIs in Javascript and you can start building 100% Javascript mobile enterprise apps today.

With all the features that RhoMobile 4 provides for you, such as access to the camera, barcode scanner or card reader, there are times where the functionality you need simply isn't there and you must resort to writing platform-native code. That process, dreaded by many, turns out not to be so hard after all. In many cases you can get away with writing very little code to achieve your needs, and it's just a case of knowing which steps to follow.

 

There is an extensive guide on writing native extensions available already but in this tutorial we will show the simplest thing that can possibly work, so that you can see the process demonstrated step by step.

 

Our future extension

 

It is often the case that the need for a native extension corresponds with the need to access some functionality that is only available in one particular platform. in this example, we will write an Android extension that tells us the path to the external SD card, so that our application can store data on it. As you may already know, in most handsets that path is "/sdcard", but there is no guarantee that the path is the same in all devices, so it is strongly discouraged to rely on hardcoded magic values. Instead, we will behave like good Android citizens and use the method provided by the platform to find out the proper path. In many cases your extensions will not require more than a few methods, so you can take this as an example of how to get started.

 

The native code

 

Because debugging native extensions gets complicated very quickly, you should first make sure that your native code works before converting it into an extension. In our case, the code required to get the path to the SD card is intentionally very simple:

 

File sdCardRoot = Environment.getExternalStorageDirectory();
String sdCardPath = sdCardRoot.getAbsolutePath();



 

 

All that remains now is how to integrate this code into a our very own RhoMobile native extension.

 

 

It all starts with an app

 

The "rhogen extension" command is in charge of generating an extension based on a predefined template that comes bundled with RMS 4.0, now is our turn to customize it. Because the official documentation already covers most of the process and options in some depth, the explanations in this tutorial will be brief, just enough to understand what's going on. You can probably solve 80% of your native extension needs by following this tutorial but remember that the more extensive documentation will help you cover the remaining 20% when you need it.

 

To make this tutorial self-contained, we will create a new application from scratch (but the same procedure applies to an existing application by skipping the "rhogen app" step).

 

From the command line, run

 

rhogen app sampleapp
cd sampleapp
rhogen extension externalstorage



 

In your application's top-level directory you will now have a new "extensions" subdirectory which, in turn, contains "externalstorage" where our new extension will live.

 

Every extension has an xml file called an API descriptor that describes (hence the name) which module and methods the extension provides. Open extensions/externalstorage/ext/externalstorage.xml and it will be similar to this:

 

<?xml version = "1.0"?>
<?xml-stylesheet type="text/xsl" href="pb_help.xsl"?>
<API>
    <MODULE name="Externalstorage" parent="Rho">
        <HELP_OVERVIEW>Example extension api</HELP_OVERVIEW>
        <MORE_HELP>This is example of API. Implementation contain in extension.</MORE_HELP>

        <TEMPLATES>
            <DEFAULT_INSTANCE/>
            <PROPERTY_BAG/>
        </TEMPLATES>


        <PROPERTIES >
            <DESC>list of properties supported by instance of object</DESC>
            <PROPERTY name="simpleStringProperty" type="STRING" usePropertyBag="accessorsViaPropertyBag" >
                <DESC>simple string property</DESC>
            </PROPERTY>
        </PROPERTIES>


        <METHODS>


            <METHOD name="enumerate" access="STATIC" hasCallback="optional">
                <RETURN type="ARRAY">
                    <DESC>Array of Externalstorage objects</DESC>
                    <PARAM type="SELF_INSTANCE"/>
                </RETURN>
            </METHOD>

            <METHOD name="getPlatformName">
                <DESC>return string with platform</DESC>
                <RETURN type="STRING"/>
            </METHOD>

            <METHOD name="calcSumm">
                <DESC>return summ of two params: a+b</DESC>
                <PARAMS>
                    <PARAM name="a" type="INTEGER">
                    </PARAM>
                    <PARAM name="b" type="INTEGER">
                    </PARAM>
                </PARAMS>
                <RETURN type="INTEGER"/>
            </METHOD>


            <METHOD name="joinStrings">
                <DESC>return join of two strings: a+b</DESC>
                <PARAMS>
                    <PARAM name="a" type="STRING">
                    </PARAM>
                    <PARAM name="b" type="STRING">
                    </PARAM>
                </PARAMS>
                <RETURN type="STRING"/>
            </METHOD>


        </METHODS>
   
        <USER_OVERVIEW>
        </USER_OVERVIEW>


        <VER_INTRODUCED>1.0.0</VER_INTRODUCED>
        <PLATFORM>
        </PLATFORM>
    </MODULE>
</API>



 

 

Although there are quite a few tags in there, you can figure out what most of them are for by their names, and the good news is, in our simple case we can remove most of them. Replace the contents of the original file with the following:

 

<?xml version = "1.0"?>
<?xml-stylesheet type="text/xsl" href="pb_help.xsl"?>
<API>
    <MODULE name="Externalstorage" parent="Rho">
        <HELP_OVERVIEW>Example extension api</HELP_OVERVIEW>
        <MORE_HELP></MORE_HELP>

        <TEMPLATES>
        </TEMPLATES>

        <PROPERTIES>
        </PROPERTIES>

        <METHODS>
            <METHOD name="getSDPath" access="STATIC">
                <PARAMS>
                </PARAMS>

                <RETURN type="STRING">
                    <DESC>Path of the SD card</DESC>
                </RETURN>
            </METHOD>                 
        </METHODS>

        <USER_OVERVIEW>
        </USER_OVERVIEW>

        <VER_INTRODUCED>1.0.0</VER_INTRODUCED>
        <PLATFORM>
        </PLATFORM>
    </MODULE>
</API>



 

We are left with a very simple file that tells us our extension will be accessed as Rho.Externalstorage in Javascript (Rho::Externalstorage in Ruby) and will have one static method called "getSDPath".

 

Every time you make changes to the API descriptor, run

 

cd extensions/externalstorage/ext
rhogen api externalstorage.xml



 

so that autogenerated files are brought in sync with your changes.

 

 

The natives are actually pretty calm and having fun

 

Time to implement our native code! Open extensions/externalstorage/ext/platform/android/generated/src/com/rho/externalstorage/IExternalstorageSingleton.java and you will see the interface that you native class must implement:

 

package com.rho.externalstorage;

import java.util.Map;
import java.util.List;

import com.rhomobile.rhodes.api.IMethodResult;

public interface IExternalstorageSingleton
{
    void getSDPath(IMethodResult result);
}



 

This file is autogenerated from the descriptor every time you make a change and it looks just like what you would expect, with the possible exception of the method being void instead of returning a value.

 

Now open extensions/externalstorage/ext/platform/android/src/com/rho/externalstorage/ExternalstorageSingleton.java

 

You will note that it says it implements the IExternalstorageSingleton you just saw, but it doesn't look like it actually does:

 

package com.rho.externalstorage;

import java.util.LinkedList;
import java.util.List;

import com.rhomobile.rhodes.api.IMethodResult;

class ExternalstorageSingleton extends ExternalstorageSingletonBase implements IExternalstorageSingleton {
    public ExternalstorageSingleton(ExternalstorageFactory factory) {
        super(factory);
    }

    List<Object> getIDs() {
        List<Object> ids = new LinkedList<Object>();
        ids.add("SCN1");
        ids.add("SCN2");
        return ids;
    }

    @Override
    protected String getInitialDefaultID() {
        return (String)(getIDs().get(0));
    }

    @Override
    public void enumerate(IMethodResult res) {
        res.set(getIDs());
    }
}



 

 

That is because this class is where your hand-written code goes. Note that the autogenerated interface was stored in .../android/generated/src/... while this is in .../android/src/... This means that the generator will never make changes to it, to make sure your code is never overwritten, and it is up to you make the appropriate changes to your implementation.

 

In our case, it will be very easy: we will remove all those methods we do not want, and add the one from the interface and any required import statements. Our class will look like this:

 

package com.rho.externalstorage;

import java.io.File;
import android.os.Environment;
import com.rhomobile.rhodes.api.IMethodResult;

class ExternalstorageSingleton extends ExternalstorageSingletonBase implements IExternalstorageSingleton {
    @Override
    public void getSDPath(IMethodResult res) {
        File sdCardRoot = Environment.getExternalStorageDirectory();
        String sdCardPath = sdCardRoot.getAbsolutePath();

        res.set(sdCardPath);
    }
}



 

Note that instead of returning a value from the method, you instead call IMethodResult.set and pass it the value you want to return (the official guide explains why this is done this way). In the same folder, open Externalstorage.java and remove all the methods in there except the constructor so that the file ends up looking like this:

 

package com.rho.externalstorage;

import java.util.Map;

import com.rhomobile.rhodes.api.IMethodResult;
import com.rhomobile.rhodes.api.MethodResult;

public class Externalstorage extends ExternalstorageBase implements IExternalstorage {

    public Externalstorage(String id) {
        super(id);
    }
}



 

You will also have to open ExternalstorageFactory.java and adapt it slightly:

 

package com.rho.externalstorage;

import com.rhomobile.rhodes.api.RhoApiFactory;

public class ExternalstorageFactory
        extends RhoApiFactory< Externalstorage, ExternalstorageSingleton>
        implements IExternalstorageFactory {

    @Override
    protected ExternalstorageSingleton createSingleton() {
        return new ExternalstorageSingleton();
    }

    @Override
    protected Externalstorage createApiObject(String id) {
        return new Externalstorage(id);
    }
}



 

 

That's all from the native side - back to the comfortable world of RhoMobile: open your build.yml and add your new extension like any other:

 

extensions: ["externalstorage"]



 

You are now ready to see the extension in action. Open an erb view file and add this simple code:

 

    <div>The path to the SD card is: <%= Rho::Externalstorage.getSDPath %></div>


    <div>
      <a onclick="alert('The path to the SD card is: '+Rho.Externalstorage.getSDPath())">Show me the path to the SD Card</a>
    </div>



 

And voila! your first native extension in action right before your eyes, accessible from Ruby and Javascript and perfectly integrated with the rest of the platform.

 

The next time you need something that RhoMobile does not offer out of the box, remember that implementing it yourself can be easier than you think.

In part 1 and 2 of this series we learned how to build a multiplatform mobile application with two-way data sync. Today we are going to see how to take advantage of asynchronous queues within RhoConnect to improve our response times and resource usage.

 

By the end of part 2, every user of our mobile application was synchronizing locally-created data with our RhoConnect server: when you saved a search on your mobile device, every other user would also get it on theirs. To do that, we implemented the “search” source adapter, to link mobile users with our sample SQLite database and allow for the basic CRUD operations. We were not communicating with Twitter to actually perform the searches that users wanted; now is the time to fix that.

 

When and how do we communicate with an external server and keep our data up to date? As always, we have several alternatives, some better than others:

 

The first option that comes to mind is, inside the “tweet” source adapter. Remember that a source adapter is the piece of code we need to write to glue our RhoConnect server together with any external data source. It seems like a reasonable place for our tweet-fetching code but there is an important caveat to keep in mind: in this code, we are going to be talking to an external server over the network and that entails high latency and potential for errors. Mobile clients would be waiting for our RhoConnect server to make a request to Twitter and receive the reply, which is generally a bad idea, as we want all our processes to be as quick as possible.

 

Can we decouple data retrieval from the external server and data synchronization with our mobile clients?

 

In our RhoConnect instance, we could start a new thread to get the information from the remote data source at defined intervals and store the results locally. All our source adapter would need to do then is get the data from our local cache and send it to the mobile client. What would happen if this task, instead of being network-bound, required heavy CPU usage? When our usage grows, we may find the need to offload it to a different machine in order to save resources on our main server.

 

Resque to the rescue

 

RhoConnect comes integrated with Resque, a library for distributed asynchronous job execution. The way it works is, you send jobs to a queue and, somewhere, on the same or a different machine, there is a set of worker processes that scan the queue and run the jobs as they come. This sounds ideal for our use case: we can run the worker processes on the same machine as our RhoConnect instance (the default) and when we start to get a lot of traffic, we will move these workers to a different server, nothing else will be affected. If the server with the workers goes down, the rest of our application will still work uninterrupted.

 

Where do we start?

The first thing we need is code to retrieve tweets from Twitter. In our tweetserver application, let’s create a “lib” folder and, within it, a file called “tweetfetcher.rb” with the following content:

 

require 'open-uri'
require 'json'



class TweetFetcher
  # Jobs must tell resque which queue they must be placed in
  def self.queue
    :tweetfetcher
  end



  # The perform method is where the job gets its work done
  def self.perform()



    # get all searches from our local database
    search_rows = Application::database.execute "Select id,query from Searches"



    search_rows.each do |search|
      begin
        search_query = URI::escape(search["query"])



        # Search twitter for our query terms - this is the 1.0 API, which is deprecated now but still works as of this writing
        # It has the advantage of not requiring authentication, making our code very simple
        uri = URI("http://search.twitter.com/search.json?q=#{search_query}&rpp=5&include_entities=false&result_type=mixed")



        search_api_results = uri.read



        json_results = JSON.parse(search_api_results)



        # Get the tweets from the response...
        twitter_results = json_results["results"]



        tweets_for_search = {}



        #... and build a hash of hashes in the format that the RhoConnect source adapter expects:
        # {
        #  "PRIMARY KEY 1" => { :property1 => :value1, :property2 => :value2 },
        #  "PRIMARY KEY 2" => { :property1 => :value1, :property2 => :value2 }
        # }



        twitter_results.each do |tweet|
          tweets_for_search[tweet["id_str"]] = { :search_id => search["id"], :status => tweet["text"]}
        end



        tweets_for_search_key = "tweets_for_search:#{search["id"]}"
        # Save our hash of hashes to Redis so that the "tweet" source adapter can find it later
        Store.put_data(tweets_for_search_key, tweets_for_search)
      rescue Exception => e
        # an error occurred - there's not much else we can do about this right now
        p "Error: #{e}"
      end
    end
  end
end


In this code, we are fetching tweets from the Twitter Search API and building a hash of hashes that the “tweet” source adapter can then return directly to mobile clients. We could also have stored just the raw results from the HTTP request, and have the source adapter parse them but by doing it this way, we are offloading any CPU-heavy processing to the worker. As we reasoned earlier, this will come handy if we have to move to a multi-server setup in the future.

 

The next step is to get this job into the queue so that it executes every now and then. Open application.rb and add the following: at the top,

 

 

require_relative "lib/tweetfetcher.rb"

 

 

and near the end, after the database method:

 

 

    def before_run
      Thread.new {
        while 1
          begin
            # Is our tweet fetching job already enqueued?
            existing_job = Resque.peek(TweetFetcher::queue)



            # If not, add it to the queue
            unless existing_job
              Resque.enqueue(TweetFetcher)
            end
          ensure
            # We will fetch tweets approximately once every 5 minutes and sleep peacefully the rest of the time
            sleep 5.minutes
          end
        end
      }
    end


We spawn a new thread in an infinite loop that looks at the queue and, if there is not a TweetFetcher job awaiting execution, it enqueues one.

 

When does this “before_run” method run? By default, never, because this is something we just made up, we need to invoke it somehow. Open config.ru and look around line 16:

 

 

 


# Load RhoConnect application
require './application'


Application.before_run


# run RhoConnect Application
run Rhoconnect.app




 

 

Just add a call to “Application.before_run” between the “require ./application” and “run Rhoconnect.app” calls.

 

Now we are ready to start the queue: open a console and run the following command:

 

 

QUEUE=tweetfetcher rake resque:work

 

 

Now the queue is online and there is a worker running jobs as they come. We can connect to redis and check that our data is there:

 

 

$ redis-cli keys tweets_for_search*

 

 

Now that we are getting the tweets, we need to forward them to the mobile app when it synchronizes with the server. That wiill be done in the “tweet” source adapter (sources/tweet.rb) and, in particular, its query method, which we must update as follows:

 

  def query(params=nil)
    @result = {}
    search_rows = Application::database.execute("Select id,query from Searches")
    search_rows.each do |search|
      search_id = search["id"]
      tweets_redis_key = "tweets_for_search:#{search_id}"
      tweets_for_search = Store.get_data(tweets_redis_key)
      
      @result.merge!(tweets_for_search)
    end
  end

 

Pretty simple, right? Just see what searches there are in our database and extract from Redis the results of our TweetFetcher job.

 

Our work is complete now, start the RhoConnect server with

 

$ rhoconnect start

 

and run the mobile application: all users will be synchronizing tweets from the server, automatically and efficiently.

 

Note that, while we completely changed the implementation of the source adapter (we were previously returning a hardcoded hash before and now we have this whole setup of distributed network requests), we did not touch the mobile application, which has continued working unchanged, oblivous to all the changes in the backend.

 

About Us:

 

Kutir Mobility is your partner in the enterprise mobile app space, empowering your team with our custom training sessions and complementing it with our own in-house development expertise. Get in touch today to schedule a free consultation with one of our mobile architects.


In part 1 of this series we built an application that received its data from a server. Today we will expand on that functionality and see how we can record data on a mobile device and have that data synchronized to all other devices connected to the same server.

 

Step 1: Update the server-side code to use a database instead of a hardcoded hash

 

Our RhoConnect source adapter (search.rb) currently returns a hardcoded result in its query method:

 

def query(params=nil)
    @result = {
      "SEARCH_1"=>{:query => "RhoMobile"},
      "SEARCH_2"=>{:query => "#fun"}
    }
  end

 

This worked great for testing purposes but now that we want to deal with user-generated data, it is not enough, so we need a real datastore. At this point we could either

 

- use the included Redis instance

- store our data in a relational database

 

Rhoconnect already uses a Redis instance as a cache for all its data handling. Whenever it receives a call from a client to retrieve information, the query method is called and the result is both sent to the client and stored in Redis for faster access next time. However, in an enterprise scenario, your data is likely to reside on a database already, so this is the approach we will take here. Note, however, that there is no limit to where your data can come from: we were using a simple hash until now, and as you will see in our new implementation, instead of querying a database you could be calling a RESTful API, reading from flat files or communicating with any other data source.

 

For demonstration purposes, we will be using SQLite and, to do that, we need some minor configuration steps. Inside the tweetserver project, open Gemfile and add the sqlite3 gem after rhoconnect:

 

gem 'rhoconnect', '3.4.4'
gem 'sqlite3'

 

You will likely have that gem installed on your system but, just in case, run

 

$ bundle install

 

on the root folder of the tweetserver project.

 

For this application, instead of every user saving his/her own searches independently of everybody else, we want everyone to share the same data and make this a collaborative effort. When one user adds a search with his mobile device, we want that search to be available to all other users automatically, so that everybody can work in harmony. This separation of data into global or user-specific buckets is called “partitioning” and can be configured in settings/settings.yml:

 

:sources:
  Search:
    :poll_interval: 3
    :partition_type: app
  Tweet:
    :poll_interval: 3
    :partition_type: app

 

By default, data from each user is isolated from everybody else, but we have configured each data source to use the partition_type called “app” (lines 4 and 7 in the listing above), which mean this is application-wide data, shared by all users.

 

As a brief reminder, in RhoConnect we created one source adapter for each entity in our application: one for Searches and one for Tweets. Each of them was returning a hardcoded hash as the result of the query method, but now we will start updating these methods to use a database instead. First of all, open application.rb and look for the initializer method. This is where we are going to set up our connection to the database:

 

def initializer(path)
      # "path" points to the root of our project, a convenient place to store our database in this example
      @database = SQLite3::Database.open(File.join(path, "tweetserver.db"))

      # We want our SQLite to return rows as hashes, with keys being column names, something like:
      # {
      #   :id => 1,
      #   :query => "example"
      # }
      #
      # Otherwise we get simple arrays like
      # [1,"example"]
      #
      # Retrieving values from arrays based on their position in the SELECT query is unnecessarily painful and prone to error
      @database.results_as_hash = true

      # The first time we run we will be working with an empty database. To make our example self-contained, we will create
      # our table here. You should not do this in a real application.
      @database.execute("create table if not exists Searches (id integer primary key autoincrement, query varchar(100))")
      super
    end

    def database
      @database
    end

 

The Application class is the entry point of our RhoConnect instance. We added some database initialization code and a simple accessor method to retrieve the connection from other places in our code. Now it is time to update the Search source adapter to use this database: open sources/search.rb, look for the query method and update it to look like this:

 

def query(params=nil)

    # Start with an empty result
    @result ={}

    # Retrieve all searches from the database...
    rows = Application::database.execute "Select id,query from Searches"

    rows.each do |row|
      # ... and add them to the result in the appropriate format:
      # {
      #   "PRIMARY KEY (as string)" => { :property1 => :value1, :property2 => :value2 }
      # }
      @result.merge!( row["id"].to_s => {:query => row["query"]} )
    end
    @result    
  end

 

This will fetch all searches from our database and return them to the mobile application. RhoConnect requires us to implement the classic four CRUD operations: Create, Read, Update and Delete. The query method corresponds to the Read operation, and there are other three methods named create, update and delete that we must implement:

 

def create(create_hash)
    Application::database.execute("insert into Searches (query) values (?)",create_hash["query"])
    # Return the primary key of the recently inserted search
    Application.database.last_insert_row_id.to_s
  end

  def update(update_hash)
    # Although "query" returns keys as strings, our database is using an integer for the ID column, hence .to_i
    Application::database.execute("update Searches set query=? where id=?", [update_hash["query"], update_hash["id"].to_i])
  end

  def delete(delete_hash)
    # Although "query" returns keys as strings, our database is using an integer for the ID column, hence .to_i
    Application::database.execute("delete from Searches where id=?", delete_hash["id"].to_i)
  end

 

That was easy: simply get the parameters from the hash and execute the appropriate query against the database. Our database is still empty, however, we have not yet provided a way for users to actually add new data to their mobile apps. Luckily, this is going to be easier than you may think at first: when we added the Search model, a few files were generated automatically for us to cover basic data creation, editing and deletion, we just have not used them until now.

 

Step 2: Update the mobile application

 

Open app/Home/index.erb and, above the list of searches, add a link to the Search controller (which was generated for us):

 

  <div data-role="content">
    <ul data-role="listview">
      <li><a href="<%= url_for :controller => :Search %>">Searches</a></li>

      <ul data-role="listview" data-inset="true">

 

(line 3 is our new link)

 

Can you believe this is all it takes to create a multi-user app with two-way synchronization? Will you trust me if I tell you that you do not need to write one more line of code?

 

Run the application and tap the “Logout” button on the home page, then tap the “Settings” icon and clear the database. Now log in as user1 again and click the new Searches link on the home page. You will see a “New” button on the top right-hand corner, use it to create a few searches and go back to the home page. Tap “Sync” to send your searches to the server, if everything goes well you should not see any changes.

 

Here comes the moment of truth.

 

Run the application on another device, or if you do not have a different device to test, close the RhoSimulator, delete the “rhosimulator” folder from your project and start the application again. This will start the application from a blank slate, as if this was a different device running the app for the first time. Log in as a different user (let’s say, user2) and... what is is we have there? those are our searches! We wanted them to be shared by all users and this is exactly what happened, the server sent them to us even if we created them as user1 and now logged in as user2 from a different device. Two-way multi-user data synchronization without breaking a sweat.

 

What’s next?

 

We already have data synchronization in place and we even interacted with a database, but we are receiving Searches only, no Tweets yet. There is a reason for that: in the next part of this series, we will use the job scheduling capabilities of Rhoconnect to populate our Tweets database at specific intervals, making efficient use of bandwith and CPU resources. Stay tuned.

 

About Us:

 

Kutir Mobility is your partner in the enterprise mobile app space, empowering your team with our custom training sessions and complementing it with our own in-house development expertise. Get in touch today to schedule a free consultation with one of our mobile architects.

In this multi-part series, you will see how quick and painless it is to build a sophisticated mobile application with two-way data synchronization, using Rhomobile Suite. No prior knowledge is required other than basic HTML and Ruby, the only prerequisite is to have Rhomobile Suite properly installed on your system.

 

Completing this tutorial will take you approximately 30 minutes, we will start from scratch and by the end of this first post you will already have developed a multiplatform mobile application that gets its data automatically from a server.

 

Today we are going to start building a twitter search client that will keep everybody in your company up to date on important topics. This, of course, is only an excuse to show you concepts and techniques that are intentionally applicable to other data sources so that you can start building data-heavy enterprise apps today.

 

Step 1. Create a Rhomobile application.

 

 

To get started creating a Rhomobile application you can use the integrated wizards in Rhostudio:

 

Captura de pantalla 2013-04-17 a la(s) 19.19.55.png

 

Captura de pantalla 2013-04-17 a la(s) 19.20.44.png

 

If you prefer the command line instead, it is equally easy:

 

$ rhodes app tweetstream

 

Both approaches will result in a new, almost blank application being created, let’s see what it looks like. We will run the application under the Rhosimulator debug environment. It will not make a difference right now whether we “run” or “debug” it, the steps are basically the same, but in the future we will want to set breakpoints and inspect variables, and knowing how to do it from the start will save us time later.

 

 

Within Rhostudio, right click the project, click “Debug As...” and click “Debug configurations”...

 

Captura de pantalla 2013-04-17 a la(s) 19.30.29.png

 

Create a new “Rhomobile Application” debug configuration

 

Captura de pantalla 2013-04-17 a la(s) 19.27.16.png

Apply your changes, click Debug and you will get something like this:

 

Captura de pantalla 2013-04-17 a la(s) 19.27.35.pngCaptura de pantalla 2013-04-17 a la(s) 19.27.42.png

 

If you are using a different IDE or a text editor, you can also start the simulator from the command line with:

 

 

 

$ rake run:iphone:rhosimulator_debug

 

 

 

Step 2. The fun begins

 

With almost no effort, we already have a native-looking base application and we can start to add our own code to it. What our application is going to do is get a list of twitter searches from a server, together with their related tweets, and we will want to see everything directly in our home screen as soon as the application starts.

 

In order to customize our home page, we are going to create a new folder under /app called Home and we will add two files there:

 

  • copy /app/index.erb into /app/Home/index.erb
  • create a new file called /app/Home/home_controller.rb with the following content:

 

 

require 'rho/rhocontroller'
require 'helpers/browser_helper'


class HomeController < Rho::RhoController
  include BrowserHelper


  # GET /Home
  def index
    render
  end
  
end

 

This controller is as simple as it gets, it will not do much yet, but it is enough to have the application render the Home screen.

 

In order to have our new controller be the starting point of the application when it opens, we need to make a small change to the rhoconfig.txt file. At the very beginning of that file you will see an entry for start_path, update it so it looks like this:

 

# startup page for your application
start_path = '/app/Home'

 

Here, "Home" matches the directory we created earlier and where we put our files. The name is not important, you could have called it anything else, but Home is descriptive for this purpose.

 

If we run the application now, not much will have changed from the first time. We will see the same screen as before, but now we are ready to start adding some of our own code.

 

Update home_controller.rb so that the index method looks like this:

 

  def index
    # we do not yet have a connection to the server, so we will test with hardcoded data
    @searches = [
      {:id => "1", :query => "rhomobile"},
      {:id => "2", :query => "#fun"}
      ]
    render
  end

 

Great, now we have some data we can test with, but they still do not appear anywhere we can see. As in any application, we need to update the view to show what we need: open /app/Home/index.erb, find the div with data-role=”content” and edit it to match the following:

 

      <div data-role="content">
          <ul data-role="listview">
            <% @searches.each do |search| %>
              <li><%= search[:query] %></li>
            <% end %>            
          </ul>
      </div>

 

Try to run the application once more and we should start to see see some changes

 

Captura de pantalla 2013-04-19 a la(s) 23.01.53.png

 

That looks better, but we are only displaying local data and our goal is to receive our information from a server; let’s see what must be done to make our application interact with the outside world. The part of RhoMobile Suite in charge of synchronization is Rhoconnect. This framework does all the heavy lifting for us, taking care of two-way data synchronization and it only asks of us that we do two things:

 

  • Add data models to our mobile app. This lets the app know which data it has to sync
  • Write a small adapter so that RhoConnect can interface with our data source. This code takes data from an external data source, be it a database, ERP system or any other service you can think of and formats the data for consumption by the mobile app

 

Let’s get started: create a new Rhoconnect application and call it “tweetserver”

 

Captura de pantalla 2013-04-19 a la(s) 23.04.58.png

 

Captura de pantalla 2013-04-19 a la(s) 23.05.39.png

 

Now, create a “Source adapter” called “Search”:

 

Captura de pantalla 2013-04-23 a la(s) 11.51.33.png

 

Or from the command line:

 

$ rhoconnect source Search

 

It is in this source adapter that our part of the magic will take place. Open /sources/search.rb, find the “query” method and change it like this:

 

 

def query(params=nil)
    @result = {
      "SEARCH_1"=>{:query => "RhoMobile"},
      "SEARCH_2"=>{:query => "#fun"}
    }
  end

 

Add another source adapter called “Tweet”, and update its query method:

 

 

def query(params=nil)
    @result = {
      "1" => {:search_id => "SEARCH_1", :status => "Rhomobile lets you leverage HTML and ruby skills for mobile development"},
      "2" => {:search_id => "SEARCH_1", :status => "This is a hardcoded tweet but at least it came from a server"},
      "3" => {:search_id => "SEARCH_2", :status => "Lorem ipsum dolor"},
      "4" => {:search_id => "SEARCH_2", :status => "consectetuer adipiscing elit"}
    }

 

 

The "query" method is called automatically by the RhoConnect synchronization engine whenever a client (our mobile app) asks if there is new data to retrieve and what RhoConnect expects us to return is a hash of hashes. In an enterprise application, instead of returning hardcoded values, we would connect to our database and issue SQL statements, or maybe call a REST API, and return the results. We will see an example of interfacing with external data servers in a future post of this series.

 

Start this RhoConnect instance, make sure it’s running and go back to the mobile app.

 

$ rhoconnect start

 

Now we have a server ready to distribute data, but our app does not yet know that. The second step to achieve data synchronization is to add a data model to the mobile application:

 

Captura de pantalla 2013-04-20 a la(s) 18.55.40.png

 

If you prefer the command line, instead of using the wizards run:

 

$ rhodes model Search query

 

 

Where “Search” is the name of the model and “query” is the only attribute this model is going to have for now.

 

Once the model is generated, we need to tell it that we want to use data synchronization: open Search/search.rb and uncomment the line that says “enable : sync”. That’s it, our mobile application will now sync searches with the server, without us having to write any code.

 

Now that the application knows how to get search data from a server, let’s update our home screen to remove our hardcoded values and instead display what the server gives us.

 

Open /app/Home/home_controller.rb, remove the hardcoded values from the index method and update it to contain the following:

 

def index
    @searches = Search.find_all
    render
end

 

What did we just do?

  • Rhomobile Suite includes Rhom, an object-relational mapper that helps us with Create, Retrieve, Update and Delete operations.
  • Search is the model we generated in the previous step, and thanks to Rhom, it comes with a few built-in methods to operate on data and make our lives easier.

 

We want to show every search on our home screen, so the find_all method is all we need, and we do not even need to write SQL. Before it can connect with the server, the application must know where that server is located. Open rhoconfig.txt and, around line 50, you will find

 

 

syncserver = ‘’

 

simply change that to read:

 

syncserver = ‘http://localhost:9292/application’

 

There is one more small change we must make in /app/Home/index.erb. Instead of

 

<%= search[:query] %>

 

now that we have a proper model we want to have

 

<%= search.query %>

 

We are almost there, but if we run our application now, the home screen will still not show any searches. Why? Because we still have not established a connection to the server. Click the “Login” button, enter “user1” as the login (anything will do, actually), leave the password empty and click “Login”.

 

Voila! we almost magically have data there now and we didn’t write any synchronization code. Isn’t enterprise mobile app development fun?

 

Now that we have the searches, let’s also show some tweets. Add another RhoMobile model called “Tweet” with a single attribute called “status” and, in the generated “Tweet/tweet.rb” file, uncomment “enable : sync” like we did previously for Search

 

The application will synchronize Searches AND Tweets now, let’s update the home screen to show them.

 

Open /app/Home/index.erb again and update the code:

 

      <div data-role="content">
          <ul data-role="listview">
            <% @searches.each do |search| %>

              <li><%= search.query %></li>

                  <ul data-role="listview" data-inset="true">
                    <% tweets_for_search(search).each do |tweet| %>
                      <li><%= tweet.status %></li>
                    <% end %>
                  </ul>

            <% end %>            
          </ul>
      </div>

 

We just added a new list under each search, to display its associated tweets by means of a new method we called “tweets_for_search”. Let’s go back to /Home/home_controller.erb in order to add the tweets_for_search method:

 

  def tweets_for_search(search)
    tweets = Tweet.find_all(
    :conditions => {
      {
      :name => :search_id
      } => search.object
    }
    )

    tweets
  end

 

What this method says is, “Find all tweets where the search_id is the current search”.

 

Run the application again and, lo and behold, there we have our searches and their tweets, all nicely displayed. While we invoked a few wizards and configured a few settings, the underlying RhoMobile platform did all the heavy lifting of data synchronization for us. That is a lot of code we do not have to write, debug or maintain and is a core part of the platform's value proposition

 

Captura de pantalla 2013-04-22 a la(s) 14.35.35.png


What’s next?

 

We are receiving data from a server, but we have not seen yet how to upload our own data to it. In the next installment of this series we will see how to create data in our mobile application and distribute it to the server and other clients.

 

About Us:

 

Kutir Mobility is your partner in the enterprise mobile app space, empowering your team with our custom training sessions and complementing it with our own in-house development expertise. Get in touch today to schedule a free consultation with one of our mobile architects.

Filter Blog

By date:
By tag: