Rhosync is a Ruby-based framework to access data from various backend applications and sync them to remote devices.
Specifically it is a Ruby on Rails application that allows managing backend application sources and user subscriptions to those data sources. It is optimized for delivery of ongoing incremental updates of those data sources to users accessing that data via mobile devices.
RhoSync retrieves data via web services (REST or SOAP) from backend enterprise applications for distribution to downstream mobile devices. It keeps a master store of all enterprise application data and keeps track of the information that users have received. It is written to be far simpler to be far simpler to deploy and configure than similar technologies that have come and gone over the past decade.
It is also more focused on the complete end to end ‘web service backend’ to mobile device (with an enabling master data store on the server) than earlier equivalents. These products were generally focused on the device endpoint syncing to a server-based database. With the success of Software as a Service (SaaS) products such as SugarCRM and SalesForce, synchronization directly to a server database is much more rarely a viable option. Instead we focus on the web service access scenario. Rhosync is also focused on arbitrary enterprise application data as opposed to being a PIM and email focused product such as Funambol.
* Ruby on Rails Version 2.2.2 * mySQL, SQLite or other database that plays nicely with Rails
sudo gem install rspec rspec-rails git clone git://github.com/rhomobile/rhosync.git cd rhosync
Then run the db:bootstrap rake task provided, creating the database and associated tables that RhoSync needs. It will also load the source adapters that we ship with.
rake db:bootstrap
Install any required gems
sudo rake gems:install
Then use your Rails server of choice to run the application. For example:
mongrel_rails start
Then you can view the Sources from your web browser:
http://localhost:3000
* we ship with an example "Source" out of the box for integrationg with SugarCRM * This is delivered in the Sources.yml files that should execute when you run the migrations. The Ruby code to interact with the backends is populated into those source records * Edit the “login”, “password” and “URL” fields if you are using one of the existing sources * Otherwise create a new Source from the application main menu and edit those same fields. * If you are using another backend you may need to create “prolog”, “call”, "createcall", "updatecall", "deletecall", “epilog” and “sync” fields with the appropriate code. See “Creating a Rhosync Datasource”
Rhosync normalizes all backend application data into a common server-based database schema, in preparation for delivering the further downstream, generally to mobile devices.
Specifically the “master server data table” is a “property bag” model, which keeps track of data sources, individual objects and the name/value pairs for those objects. This allows handling of diverse backend application data structures within a single master store. It also provides for efficient delivery of single “fields” of data in either direction (e.g. just the status changing of a trouble ticket).
The connection code for logging into a backend application (via REST or SOAP APIs), calling the data retrieval and update functions, logging off, and populating the master data table are each written in Ruby but stored in the application sources table. The schema for this table and other tables involved in supporting this functionality are as described below.
There are two important tables that describe fully the universe of data sources and their contents for downstream syncing. These are the SOURCES table and the OBJECT_VALUES table (and the corresponding Source and ObjectValues models. Other tables include tables to keep of the mobile device users and their subscriptions to the various data sources available.
A “property bag” schema that facilitatest importing any kind of data into a common table for later distribution to downstream clients.
* object – the unique identifier of the object (generally an integer “record ID” from the backend system) * attribute – the name of the attribute (e.g. “Account Name”, “Industry”) * value – the value of the attribute (e.g. “Acme Corp”, “software”) * source_id – reference back to the source (see below) used for syncing
This table contains all of the information necessary to connect to a given backend system. These includes the URL to connect to and authentication information.
* URL – the URL to connect to (for REST adapters) or the URL to the WSDL (for SOAP services) * SERVER – OPTIONAL a logical name for the data source server (AcmeCorpSugar) * LOGIN – the username or logon ID for the backend * PASSWORD – password (stored in the clear right now) for the backend system
Backend Code Columns
* PROLOG – a set of Ruby code generally for logging into the backend system. Generally this is a SOAP or REST call which populates a session_id variable (that variable must be used in the call code below). * CALL – the actual code for getting data back (generally uses the session_id acquired in the prolog) * CREATECALL - code to create records in the backend from the object values table * UPDATECALL - update code for the backend * DELETECALL - record deletion code for the backend * LOGOUT – OPTIONAL, code to logoff the backend system * SYNC – this is the code used to take apart the returned data and stuff it into the OBJECT_VALUES property bag table. Theoretically this could be done in the CALL column.
This is a sample source adapter to retrieve Sugar Account objects.
sugar:
id: 1 name: RhoSugar url: http://rhomobile.com/sugar/soap.php?wsdl login: admin password: acc3ss$ugar prolog: | u = @source.login p = Digest::MD5.hexdigest(@source.password) ua = {'user_name' => u,'password' => p} ss = client.login(ua,nil) if ss.error.number.to_i != 0 p 'failed to login - #{ss.error.description}' return else session_id = ss['id'] uid = client.get_user_id(session_id) end call: | module_name = 'Accounts' query = '' # gets all the acounts, you can also use SQL like 'accounts.name like '%company%'' order_by = '' # in default order. you can also use SQL like 'accounts.name' offset = 0 select_fields = ['name','industry'] # this can't be an empty array max_results = '10000' # if set to 0 or '', this doesn't return all the results deleted = 0 # whether you want to retrieve deleted records, too result = client.get_entry_list(session_id,module_name,query,order_by,offset,select_fields,max_results,deleted); sync: | result.entry_list.each do |x| x.name_value_list.each do |y| o=ObjectValue.new [email protected] o.object=x['id'] o.attrib=y.name o.value=y.value o.update_type='query' o.save end end createcall: # name_value_list is passed in and can be used in the code below # for creates we just assume that the primary keys (if fields) are left out result=client.set_entry(session_id,'Accounts',name_value_list); p result.inspect.to_s updatecall: # name_value_list is passed in and can be used in the code below result=client.set_entry(session_id,'Accounts',name_value_list); p result.inspect.to_s deletecall: name_value_list.push({'name'=>'deleted','value'=>'1'}); result=client.set_entry(session_id,'Accounts',name_value_list); p result.inspect.to_s epilog: client.logout(session_id)
Send questions to [email protected]