rhoconnect 3.0.6 → 3.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +9 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +38 -17
- data/Rakefile +0 -10
- data/bench/benchapp/Gemfile.lock +1 -0
- data/bench/distr_bench/distr_bench_main +94 -27
- data/bench/distr_bench/run_test_query_script.sh +22 -18
- data/bench/lib/bench/aws_utils.rb +326 -0
- data/bench/lib/bench/bench_result_processor.rb +268 -75
- data/bench/lib/bench/cli.rb +1 -0
- data/bench/lib/bench/distr_runner.rb +102 -0
- data/bench/lib/bench/utils.rb +127 -0
- data/bench/lib/bench.rb +16 -15
- data/bench/prepare_bench +3 -11
- data/bench/scripts/test_query_script.rb +6 -7
- data/bin/rhoconnect-benchmark +257 -5
- data/doc/benchmarks-running.txt +140 -0
- data/doc/client-java.txt +236 -0
- data/doc/client-objc.txt +41 -1
- data/doc/client.txt +12 -0
- data/doc/command-line.txt +12 -3
- data/doc/cud-conflicts.txt +68 -0
- data/doc/deploying.txt +1 -70
- data/doc/hosting-rhohub.txt +3 -0
- data/doc/install.txt +50 -13
- data/doc/java-plugin.txt +217 -177
- data/doc/net-plugin.txt +97 -64
- data/doc/plugin-intro.txt +4 -2
- data/doc/preparing-production.txt +63 -0
- data/doc/rhoconnect-redis-stack.txt +252 -0
- data/doc/source-adapters.txt +3 -1
- data/doc/tutorial.txt +111 -49
- data/examples/simple/dump.rdb +0 -0
- data/installer/unix-like/rho_connect_install_constants.rb +6 -5
- data/installer/unix-like/rho_connect_install_installers.rb +6 -2
- data/installer/utils/nix_install_test.rb +2 -0
- data/installer/utils/package_upload/auto-repo.rb +136 -0
- data/installer/utils/package_upload/repos.rake +6 -3
- data/installer/utils/package_upload/s3_upload.rb +11 -6
- data/installer/windows/rhosync.nsi +5 -5
- data/lib/rhoconnect/client_sync.rb +2 -2
- data/lib/rhoconnect/document.rb +12 -0
- data/lib/rhoconnect/jobs/source_job.rb +2 -2
- data/lib/rhoconnect/predefined_adapters/bench_adapter.rb +61 -0
- data/lib/rhoconnect/source.rb +5 -0
- data/lib/rhoconnect/source_adapter.rb +10 -1
- data/lib/rhoconnect/source_sync.rb +161 -88
- data/lib/rhoconnect/store.rb +48 -0
- data/lib/rhoconnect/test_methods.rb +6 -6
- data/lib/rhoconnect/version.rb +1 -1
- data/lib/rhoconnect.rb +25 -2
- data/spec/apps/rhotestapp/sources/sample_adapter.rb +29 -0
- data/spec/jobs/source_job_spec.rb +5 -5
- data/spec/source_adapter_spec.rb +10 -0
- data/spec/source_sync_spec.rb +114 -33
- data/spec/spec_helper.rb +21 -2
- data/spec/store_spec.rb +29 -0
- data/spec/support/shared_examples.rb +1 -1
- data/spec/test_methods_spec.rb +4 -4
- data/tasks/redis.rake +2 -2
- metadata +59 -59
- data/bench/benchapp/log/passenger.3000.log +0 -1
- data/bench/benchapp/log/passenger.9292.log +0 -59
- data/bench/benchapp/tmp/pids/passenger.3000.pid.lock +0 -0
- data/bench/benchapp/tmp/pids/passenger.9292.pid.lock +0 -0
- data/bench/lib/testdata/0-data.txt +0 -0
- data/bench/lib/testdata/1-data.txt +0 -0
- data/bench/lib/testdata/10-data.txt +0 -15
- data/bench/lib/testdata/2-data.txt +0 -3
- data/bench/lib/testdata/25-data.txt +0 -39
- data/bench/lib/testdata/250-data.txt +0 -353
- data/bench/lib/testdata/3-data.txt +0 -4
- data/bench/lib/testdata/50-data.txt +0 -70
- data/bench/lib/testdata/500-data.txt +0 -711
@@ -0,0 +1,140 @@
|
|
1
|
+
Running RhoConnect Benchmarks
|
2
|
+
===
|
3
|
+
|
4
|
+
## Introduction
|
5
|
+
|
6
|
+
You can execute benchmark tests against your deployment and verify the performance of your Rhoconnect application using the provided `rhoconnect-benchmark` command.
|
7
|
+
During the test the Rhoconnect benchmark framework will dynamically create a special ephemeral source adapter inside of
|
8
|
+
your application and perform the 5-step query use-case mimicking the typical device-to-server communication.
|
9
|
+
|
10
|
+
Currently, the Rhoconnect Benchmark measures two primary system-wide metrics: Average Time and Throughput.
|
11
|
+
|
12
|
+
- Average time (milliseconds per request) is calculated as sum_of_executed_http_request_times/number of http requests.
|
13
|
+
- Throughput is an integral metric (number of requests per second) calculated as: cumulative_number_of_http_requests_processed/(finish_time_for_last_test - start_time_of_first_test).
|
14
|
+
|
15
|
+
NOTE: Both metrics implicitly include the network latency and therefore represent the performance of the whole system `device-network-server`.
|
16
|
+
|
17
|
+
## Rhoconnect Benchmark Command
|
18
|
+
|
19
|
+
To execute the Rhoconnect Benchmark test, use the `rhoconnect-benchmark` command. This command has the following options:
|
20
|
+
|
21
|
+
<table border="1">
|
22
|
+
<tr>
|
23
|
+
<td width="20">-u</td>
|
24
|
+
<td width="200"><code>--url URL</code></td>
|
25
|
+
<td>Use URL to specify the targeted Rhoconnect server for benchmarking. If this option is not specified, <code>http://localhost:9292</code> will be used as a default.</td>
|
26
|
+
</tr>
|
27
|
+
<tr>
|
28
|
+
<td width="20">-p</td>
|
29
|
+
<td width="200"><code>--payload NUMBER</code></td>
|
30
|
+
<td>This options specifies the amount of data to be simulated in the query request (in number of records). Default: 100, which roughly translates into 20 kilobytes.</td>
|
31
|
+
</tr>
|
32
|
+
<tr>
|
33
|
+
<td width="20">-C</td>
|
34
|
+
<td width="200"><code>--nclients NUMBER</code></td>
|
35
|
+
<td>Specifies how many concurrent clients to emulate during the test. If this option is omitted, then the number of simulated clients will be determined based on the number of available seats in your Rhoconnect application's license.</td>
|
36
|
+
</tr>
|
37
|
+
<tr>
|
38
|
+
<td width="20">-R</td>
|
39
|
+
<td width="200"><code>--niterations NUMBER</code></td>
|
40
|
+
<td>Specifies how many times each emulated client will perform the test. Default: 10. The more iterations you specify, the more time your test will take, but it will lessen the test result's statistical fluctuations.</td>
|
41
|
+
</tr>
|
42
|
+
<tr>
|
43
|
+
<td width="20">-S</td>
|
44
|
+
<td width="200"><code>--save PATH</code></td>
|
45
|
+
<td>This option saves the test results in the PATH sub-directory and run the post-processing on the saved files (for example, generate the EXCEL spreadsheet). All the results will be saved under the PATH root directory.</td>
|
46
|
+
</tr>
|
47
|
+
<tr>
|
48
|
+
<td width="20">-x</td>
|
49
|
+
<td width="200"><code>--maxpayloadloops NUMBER</code></td>
|
50
|
+
<td>This option runs several tests in a loop varying the payload between 1 and NUMBER. The specified interval will be split by 10. For example: -m 500 will produce 10 test executions , first for payload of 1 record, then - for 56, 112, 167, 223, 278, 334, 389, 445, and 500</td>
|
51
|
+
</tr>
|
52
|
+
<tr>
|
53
|
+
<td width="20">-m</td>
|
54
|
+
<td width="200"><code>--maxclientloops NUMBER</code></td>
|
55
|
+
<td>This option runs several tests in a loop varying number of concurrent clients between 1 and NUMBER. The specified interval will be split by 5. For example: -m 10 will produce 5 test executions , first for 1 client, then - for 3, 6, 8, and 10</td>
|
56
|
+
</tr>
|
57
|
+
<tr>
|
58
|
+
<td width="20">-A</td>
|
59
|
+
<td width="200"><code>--advanced</code></td>
|
60
|
+
<td>This convenience option combines -m 10, -x 500, and -S <cur_dir/bench_results> - thus running a matrix of tests varying in payload and number of concurrent clients. Also, it saves the results into the `bench_results` subdirectory and runs the available post-processing.</td>
|
61
|
+
</tr>
|
62
|
+
<tr>
|
63
|
+
<td width="20">-D</td>
|
64
|
+
<td width="200"><code>--distributed AWSFILE</code></td>
|
65
|
+
<td>This option executes the advanced benchmark test using the remote AWS EC2 clients. Currently, this option is only available for the Linux/MacOS machines. See Distributed Benchmark section below for details.</td>
|
66
|
+
</tr>
|
67
|
+
</table>
|
68
|
+
|
69
|
+
## Result post-processing
|
70
|
+
By default, all results are displayed in the console during the test. However, it is possible to save all the results into the file and, additionally, generate the EXCEL files and/or PNG images using the `--save PATH` option. The results are saved for two benchmark metrics: Average Time and Throughput.
|
71
|
+
|
72
|
+
### Generate EXCEL spreadsheet
|
73
|
+
To enable the automatic generation of the EXCEL spreadsheets from the test results, please install the `spreadsheet` gem by using:
|
74
|
+
|
75
|
+
$ [sudo] gem install spreadsheet
|
76
|
+
|
77
|
+
You can read more about the `spreadsheet` gem [here](http://rubygems.org/gems/spreadsheet).
|
78
|
+
|
79
|
+
### Generate PNG images
|
80
|
+
To enable the automatic generation of the PNG images from the test results, install the `gruff` gem.
|
81
|
+
Installation of the GRUFF gem requires an additional installation of several components.
|
82
|
+
Use [this](http://nubyonrails.com/pages/gruff) guide to install the GRUFF on your machine.
|
83
|
+
|
84
|
+
## Distributed Benchmark test
|
85
|
+
To fully simulate the distributed nature of the device-to-server system, the Rhoconnect Benchmark command allows to you to create distributed clients through the [AWS Cloud Formation](http://aws.amazon.com/cloudformation/).
|
86
|
+
|
87
|
+
NOTE: Distributed Rhoconnect Benchmark test will be executed via the AWS Cloud Formation and EC2 services using your account and therefore you will be billed for its usage by Amazon.
|
88
|
+
|
89
|
+
In order to run the distributed Benchmark test, you need to have an AWS account and specify its settings in a YAML file, which should have the following structure:
|
90
|
+
|
91
|
+
:::ruby
|
92
|
+
:default:
|
93
|
+
:region: desired_aws_region
|
94
|
+
:aws_access_key_id: your_aws_account_key_id
|
95
|
+
:aws_secret_access_key: your_aws_account_secret_access_key
|
96
|
+
:aws_key_pair_name: your_aws_ec2_security_key_pair
|
97
|
+
:aws_ssh_pem_file: location_of_your_aws_ssh_pem_file
|
98
|
+
|
99
|
+
Here is the description of each entry in the AWS settings file:
|
100
|
+
|
101
|
+
<table border="1">
|
102
|
+
<tr>
|
103
|
+
<td width="300"><code>:region</code></td>
|
104
|
+
<td>Specify the desired AWS region for your EC2 clients. Default is 'us-west-1'. Typically, you need to specify the same region as the location of your Rhoconnect server to minimize the network impact (since communications between different regions will take more time).</td>
|
105
|
+
</tr>
|
106
|
+
<tr>
|
107
|
+
<td width="200"><code>:aws_access_key_id</code></td>
|
108
|
+
<td>Your AWS access key ID.</td>
|
109
|
+
</tr>
|
110
|
+
<tr>
|
111
|
+
<td width="200"><code>:aws_secret_access_key</code></td>
|
112
|
+
<td>Your AWS secret access key.</td>
|
113
|
+
</tr>
|
114
|
+
<tr>
|
115
|
+
<td width="200"><code>:aws_key_pair_name</code></td>
|
116
|
+
<td>In order to create EC2 clients, you will need to create EC2 KeyPair in the desired region. After that KeyPair is created, you will have its name, which should be specified here.</td>
|
117
|
+
</tr>
|
118
|
+
<tr>
|
119
|
+
<td width="200"><code>:aws_ssh_pem_file</code></td>
|
120
|
+
<td>For the above KeyPair, you will have the corresponding keypair .PEM file. Download this file to your machine and reference its location here.</td>
|
121
|
+
</tr>
|
122
|
+
</table>
|
123
|
+
|
124
|
+
Once the AWS settings file is created, you need to make sure that the following gems are installed on your machine:
|
125
|
+
|
126
|
+
- fog
|
127
|
+
- net-ssh-multi
|
128
|
+
|
129
|
+
You can install those gems using the `[sudo] gem install <gemname>` command.
|
130
|
+
|
131
|
+
Once all the pre-requisites are met, you can run the distributed Rhoconnect Benchmark test with the following command:
|
132
|
+
|
133
|
+
$ rhoconnect-benchmark -u `server_url` -D `path_to_aws_settings_file`
|
134
|
+
|
135
|
+
|
136
|
+
NOTE: In order to run the distributed Benchmark test, you must provide public server's URL accessible from the outside clients.
|
137
|
+
|
138
|
+
|
139
|
+
|
140
|
+
|
data/doc/client-java.txt
ADDED
@@ -0,0 +1,236 @@
|
|
1
|
+
# Android Java Client
|
2
|
+
|
3
|
+
## Getting started
|
4
|
+
|
5
|
+
* The RhoConnect Client is part of the Rhodes repository. You can get it [on github](https://github.com/rhomobile/rhodes/downloads) (select the latest 'rhoconnect-client' package).
|
6
|
+
|
7
|
+
* The RhoConnect Client for Android contains two files:
|
8
|
+
|
9
|
+
** rhoimpl.jar - Java part of RhoConnect Client library
|
10
|
+
|
11
|
+
** librhoconnectclient.so - native part of RhoConnect Client library
|
12
|
+
|
13
|
+
These can be build from <rhodes>/rhoconnect-client directory with next command
|
14
|
+
|
15
|
+
:::shell
|
16
|
+
$>rake android:default
|
17
|
+
|
18
|
+
* Create new Android project or open existing one in Eclipse. Add rhoimple.jar to your project build path and copy librhoconnectclient.so to <project_root>/libs/armeabi, so both Java and native parts of RhoConnect Client library will link with your project.
|
19
|
+
|
20
|
+
* Copy all files and subfolders from <rhodes>/rhoconnect-client/Java/RhoConnect/assets to assets folder of your Android project.
|
21
|
+
|
22
|
+
## RhoConnectClient initialization
|
23
|
+
|
24
|
+
* Load native library before any RhoConnect client usage. Example of appropriate place to do so is Android application's onCreate method
|
25
|
+
|
26
|
+
:::java
|
27
|
+
|
28
|
+
import android.app.Application;
|
29
|
+
public class SampleApplication extends Application
|
30
|
+
{
|
31
|
+
public void onCreate() {
|
32
|
+
System.loadLibrary("rhoconnectclient");
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
* Configure and initialize RhoConnect library. Example of appropriate place to do so is main Activity onCreate method
|
37
|
+
|
38
|
+
* Login to RhoConnect server
|
39
|
+
|
40
|
+
:::cplusplus
|
41
|
+
public void onCreate(Bundle savedInstanceState) {
|
42
|
+
super.onCreate(savedInstanceState);
|
43
|
+
setContentView(R.layout.main);
|
44
|
+
|
45
|
+
ApplicationInfo appInfo = getApplicationInfo();
|
46
|
+
|
47
|
+
try {
|
48
|
+
RhoFileApi.initRootPath(appInfo.dataDir, appInfo.sourceDir);
|
49
|
+
RhoFileApi.init(this.getApplicationContext());
|
50
|
+
|
51
|
+
RhoLogConf.setMinSeverity(0);
|
52
|
+
RhoLogConf.setEnabledCategories("*");
|
53
|
+
|
54
|
+
RhoConnectClient.nativeInit();
|
55
|
+
} catch (Exception e) {
|
56
|
+
Logger.E(TAG, e.getMessage());
|
57
|
+
}
|
58
|
+
mSyncClient = new RhoConnectClient();
|
59
|
+
mModels = new RhomModel[]{
|
60
|
+
new RhomModel("Customer", RhomModel.SYNC_TYPE_INCREMENTAL),
|
61
|
+
new RhomModel("Product", RhomModel.SYNC_TYPE_INCREMENTAL)
|
62
|
+
};
|
63
|
+
mSyncClient.initialize(mModels);
|
64
|
+
mSyncClient.setPollInterval(0);
|
65
|
+
mSyncClient.setSyncServer("http://rhodes-store-server.heroku.com/application");
|
66
|
+
mSyncClient.setBulkSyncState(1);
|
67
|
+
mSyncClient.loginWithUserAsync("", "", new RhoConnectNotify.IDelegate() {
|
68
|
+
public void call(RhoConnectNotify notify) { onLogin(notify); } });
|
69
|
+
}
|
70
|
+
public void onLogin(RhoConnectNotify notify) {
|
71
|
+
// Handle login event
|
72
|
+
}
|
73
|
+
|
74
|
+
Note: RhoConnect callbacks (like passed to RhoConnectClient.loginWithUserAsync methodin axample above) may and most possibly will be called from another thread. It is up to application developer to care about synchronizing or forwarding call to an appropriate thread like GUI thread or Service thread.
|
75
|
+
|
76
|
+
## Object Model
|
77
|
+
|
78
|
+
### Intro
|
79
|
+
|
80
|
+
RhoConnect Client Android Java API resides at com.rhomobile.rhoconnect pakage. It contains two main classes: RhoConnectClient and RhomModel. The package also contains two classes which represent results of call to the API. These are RhoConnectNotify and RhoConnectObjectNotify.
|
81
|
+
Also several utility classes from com.rhomobile.rhodes package can be used. These are RhoConf, RhoLogConf, Logger.
|
82
|
+
|
83
|
+
### RhoConnectClient
|
84
|
+
|
85
|
+
:::cplusplus
|
86
|
+
package com.rhomobile.rhoconnect;
|
87
|
+
public class RhoConnectClient{
|
88
|
+
/// Call this method before create and use the client. It sets up directory structure and makes nessesary native library initialization.
|
89
|
+
public static native void nativeInit();
|
90
|
+
/// Creates instance of RhoConnectClient singlethon (yes, it's only one instance of RhoConnectClient allowed).
|
91
|
+
public RhoConnectClient();
|
92
|
+
/// Call this method to close network connections and release any resources gracefully
|
93
|
+
public synchronized void close();
|
94
|
+
/// Makes db models initialization. This call must be made just after RhoConnectClient construction and before any other calls to RhoConnectClient object.
|
95
|
+
public native void initialize(RhomModel models[]);
|
96
|
+
/// Sets up server URL to sync (RhoConnect server)
|
97
|
+
public native void setSyncServer(String url);
|
98
|
+
/// Forces synchronous or asynchronous RhoConnectClient mode
|
99
|
+
/// true - asynchronous mode (default)
|
100
|
+
/// false - synchronous mode
|
101
|
+
public native void setThreadedMode(boolean mode);
|
102
|
+
/// Sets/gets auto sync interval. 0 - disable auto sync
|
103
|
+
public native void setPollInterval(int interval);
|
104
|
+
public native int getPollInterval();
|
105
|
+
///
|
106
|
+
public native void setBulkSyncState(int state);
|
107
|
+
public native int getBulkSyncState();
|
108
|
+
/// Set get various configuration parameters.
|
109
|
+
public native void setConfigString(String name, String param);
|
110
|
+
public native String getConfigString(String name);
|
111
|
+
/// Reset all data for all models in local database, also perform logout
|
112
|
+
public native void databaseFullResetAndLogout();
|
113
|
+
/// Checks does login session exists in the database
|
114
|
+
public native boolean isLoggedIn();
|
115
|
+
/// Logins to RhoConnect server and keep login session in database
|
116
|
+
public native RhoConnectNotify loginWithUserSync(String user, String pass);
|
117
|
+
/// Logins to RhoConnect server and keep login session in database.
|
118
|
+
/// callback will be called when operation has finished.
|
119
|
+
public native void loginWithUserAsync(String user, String pass, RhoConnectNotify.IDelegate callback);
|
120
|
+
/// Runs sync of all models
|
121
|
+
public native RhoConnectNotify syncAll();
|
122
|
+
}
|
123
|
+
|
124
|
+
### RhomModel
|
125
|
+
|
126
|
+
:::cplusplus
|
127
|
+
package com.rhomobile.rhoconnect;
|
128
|
+
public class RhomModel {
|
129
|
+
/// Possible model types
|
130
|
+
public final static int MODEL_TYPE_PROPERTY_BAG = 0;
|
131
|
+
public final static int MODEL_TYPE_FIXED_SCHEMA = 1;
|
132
|
+
/// Possible sync types
|
133
|
+
public final static int SYNC_TYPE_NONE = 0;
|
134
|
+
public final static int SYNC_TYPE_INCREMENTAL = 1;
|
135
|
+
public final static int SYNC_TYPE_BULK_ONLY = 2;
|
136
|
+
/// Constructor
|
137
|
+
public RhomModel(String name, int syncType);
|
138
|
+
/// Returns the model name
|
139
|
+
public String getName() { return mName; }
|
140
|
+
/// Returns the model type
|
141
|
+
public int getModelType() { return mModelType; }
|
142
|
+
/// Sets the model type
|
143
|
+
public void setModelType(int type) { mModelType = type; }
|
144
|
+
// Returns the model sync type
|
145
|
+
public int getSyncType() { return mSyncType; }
|
146
|
+
/// Sets the model sync type
|
147
|
+
public void setSyncType(int type) { mSyncType = type; }
|
148
|
+
/// Returns the model sync priority
|
149
|
+
public int getSyncPriority() { return mSyncPriority; }
|
150
|
+
/// Sets the model sync priority
|
151
|
+
public void setSyncPriority(int prio) { mSyncPriority = prio; }
|
152
|
+
/// Returns the model partition
|
153
|
+
public String getPartition() { return mPartition; }
|
154
|
+
/// Sets the model partition
|
155
|
+
public void setPartition(String part) { mPartition = part; }
|
156
|
+
/// Runs sync of the model
|
157
|
+
public RhoConnectNotify sync();
|
158
|
+
/// Creates model object with properties and save to database, object id will be generated automatically if not set
|
159
|
+
public void create(Map<String, String> props);
|
160
|
+
/// Finds object by object id
|
161
|
+
public Map<String, String> find(String objectId)
|
162
|
+
/// Saves changes to existing object
|
163
|
+
public void save(Map<String, String> item);
|
164
|
+
/// Destroys existing object
|
165
|
+
public void destroy(Map<String, String> item) {
|
166
|
+
|
167
|
+
// Returns first object which matches the condition
|
168
|
+
public Map<String, String> findFirst(Map<String, String> condition);
|
169
|
+
// Returns all objects which matched the condition
|
170
|
+
public Collection<Map<String, String> > findAll(Map<String, String> condition);
|
171
|
+
|
172
|
+
public void startBulkUpdate();
|
173
|
+
public void stopBulkUpdate();
|
174
|
+
}
|
175
|
+
|
176
|
+
#### RhoConnectNotify
|
177
|
+
|
178
|
+
:::cplusplus
|
179
|
+
package com.rhomobile.rhoconnect;
|
180
|
+
public class RhoConnectNotify {
|
181
|
+
public int getTotalCount() { return mTotalCount; }
|
182
|
+
public int getProcessedCount() { return mProcessedCount; }
|
183
|
+
public int getCumulativeCount() { return mCumulativeCount; }
|
184
|
+
public int getSourceId() { return mSourceId; }
|
185
|
+
public int getErrorCode() { return mErrorCode; }
|
186
|
+
public String getSourceName() { return mSourceName; }
|
187
|
+
public String getStatus() { return mStatus; }
|
188
|
+
public String getSyncType() { return mSyncType; }
|
189
|
+
public String getErrorMessage()
|
190
|
+
public String getCallbackParams() { return mParams; }
|
191
|
+
/// Developer need to implement and pass reference to this interface
|
192
|
+
/// in order to get call back when asynchronous operation has completed
|
193
|
+
public static interface IDelegate {
|
194
|
+
public void call(RhoConnectNotify notify);
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
#### RhoConnectObjectNotyfy
|
199
|
+
|
200
|
+
:::cplusplus
|
201
|
+
package com.rhomobile.rhoconnect;
|
202
|
+
public interface RhoConnectObjectNotify {
|
203
|
+
public String[] getDeletedObjects();
|
204
|
+
public String[] getUpdatedObjects();
|
205
|
+
public String[] getCreatedObjects();
|
206
|
+
|
207
|
+
public int[] getDeletedSourceIds();
|
208
|
+
public int[] getUpdatedSourceIds();
|
209
|
+
public int[] getCreatedSourceIds();
|
210
|
+
|
211
|
+
/// Developer need to implement and pass reference to this interface
|
212
|
+
/// in order to get call back when objects are created, updated or destroyed at sync server
|
213
|
+
public static interface IDelegate {
|
214
|
+
public void call(RhoConnectObjectNotify notify);
|
215
|
+
}
|
216
|
+
}
|
217
|
+
|
218
|
+
### Samples
|
219
|
+
|
220
|
+
* See android_store sample [rhoconnect-client\Samples\Java\android_store](http://github.com/rhomobile/rhodes/tree/master/rhoconnect-client/Samples/Java/android_store/) as an example.
|
221
|
+
* See android test Eclipse project [rhoconnect-client\Java\Android\test](http://github.com/rhomobile/rhodes/tree/master/rhoconnect-client/Java/Android/test/) as another example.
|
222
|
+
|
223
|
+
## Packaging RhoConnect Client
|
224
|
+
To package the RhoConnect Client archive for distribution, go to the top of the rhodes repository and run:
|
225
|
+
|
226
|
+
:::term
|
227
|
+
$ rake build:rhoconnect_client
|
228
|
+
|
229
|
+
This will produce a zipfile in the folder called `rhoconnect-client-<someversion>.zip` where `<someversion>` is the version of the client.
|
230
|
+
|
231
|
+
## Release procedure
|
232
|
+
1. Unzip package to some folder
|
233
|
+
|
234
|
+
2. Open project `rhoconnect-client\ObjectiveC\Tests\RhoConnectClientTest` in xcode and run. See log - SUCCESS should be at the end of log
|
235
|
+
|
236
|
+
3. Open project `rhoconnect-client\Samples\ObjectiveC\store` in xcode and run. Press Login, you should see several items, click on item, you should see details
|
data/doc/client-objc.txt
CHANGED
@@ -146,7 +146,8 @@ Here is the Store code for the initialization process, contained in RhoConnectEn
|
|
146
146
|
|
147
147
|
sclient.sync_server = @"http://rhodes-store-server.heroku.com/application";
|
148
148
|
sclient.threaded_mode = TRUE;
|
149
|
-
|
149
|
+
sclient.log_severity = 1;
|
150
|
+
|
150
151
|
loginState = [sclient is_logged_in] ? logged_in : logged_out;
|
151
152
|
}
|
152
153
|
return sharedInst;
|
@@ -190,6 +191,13 @@ Call the RhoConnectClient setNotification method to call a callback method that
|
|
190
191
|
:::cplusplus
|
191
192
|
[ [RhoConnectEngine sharedInstance].syncClient setNotification: @selector(syncAllComplete:) target:self];
|
192
193
|
|
194
|
+
To perform a bulk sync *bulksync_state* configuration flag should be reset to zero. If you don't need bulk sync then just skip it.
|
195
|
+
|
196
|
+
:::cplusplus
|
197
|
+
// set configuration for bulk sync, it means "next sync should be performed as bulk"
|
198
|
+
[RhoConnectEngine sharedInstance].syncClient.bulksync_state = 0;
|
199
|
+
// after sync performed the it should contain value 1.
|
200
|
+
|
193
201
|
Call a sync method, such as the RhoConnectClient syncAll method or the RhomModel sync method, to sync your client model data with the RhoConnect server.
|
194
202
|
|
195
203
|
:::cplusplus
|
@@ -391,6 +399,7 @@ The RhoConnectClient class contains the following properties and methods to buil
|
|
391
399
|
|
392
400
|
* <a href="#threaded_mode">threaded_mode property</a>
|
393
401
|
* <a href="#poll_interval">poll_interval property</a>
|
402
|
+
* <a href="#log_severity">log_severity property</a>
|
394
403
|
* <a href="#sync_server">sync_server property</a>
|
395
404
|
* <a href="#initDatabase">initDatabase</a>
|
396
405
|
* <a href="#addModels">addModels</a>
|
@@ -403,6 +412,8 @@ The RhoConnectClient class contains the following properties and methods to buil
|
|
403
412
|
* <a href="#clearNotification">clearNotification</a>
|
404
413
|
* <a href="#is_logged_in">is\_logged\_in</a>
|
405
414
|
* <a href="#syncAll">syncAll</a>
|
415
|
+
* <a href="#is_syncing">is_syncing</a>
|
416
|
+
* <a href="#stop_sync">stop_sync</a>
|
406
417
|
* <a href="#search">search</a>
|
407
418
|
* <a href="#setObjectNotification">setObjectNotification</a>
|
408
419
|
* <a href="#clearObjectNotification">clearObjectNotification</a>
|
@@ -425,6 +436,13 @@ int. Not yet supported. Default = 0.
|
|
425
436
|
:::cplusplus
|
426
437
|
@property(setter=setPollInterval) int poll_interval;
|
427
438
|
|
439
|
+
### <a id="log_severity"></a>log\_severity property
|
440
|
+
|
441
|
+
int. Set minimal severity level for messages to log output. Default = 0.
|
442
|
+
|
443
|
+
:::cplusplus
|
444
|
+
@property(setter=setLogSeverity) int log_severity;
|
445
|
+
|
428
446
|
### <a id="sync_server"></a>sync\_server property
|
429
447
|
|
430
448
|
NSString. Sets the RhoConnect server url, for example: "`http://<ip>:<port>/application`"
|
@@ -542,6 +560,20 @@ Instance method. Returns a RhoConnectNotify object after running a sync on all t
|
|
542
560
|
:::cplusplus
|
543
561
|
- (RhoConnectNotify*) syncAll;
|
544
562
|
|
563
|
+
### <a id="is_syncing">is_syncing
|
564
|
+
|
565
|
+
Instance method. Returns TRUE if syncronization is in progress
|
566
|
+
|
567
|
+
:::cplusplus
|
568
|
+
- (BOOL) is_syncing;
|
569
|
+
|
570
|
+
### <a id="stop_sync">stop_sync
|
571
|
+
|
572
|
+
Instance method. Stop current sync if running
|
573
|
+
|
574
|
+
:::cplusplus
|
575
|
+
- (void) stop_sync;
|
576
|
+
|
545
577
|
### <a id="search">search
|
546
578
|
|
547
579
|
Instance method. Returns a RhoConnectNotify object after sending a search request to the RhoConnect server.
|
@@ -717,6 +749,7 @@ The RhomModel class contains the following properties and methods for setting an
|
|
717
749
|
* <a href="#destroy">destroy</a>
|
718
750
|
* <a href="#startBulkUpdate">startBulkUpdate</a>
|
719
751
|
* <a href="#stopBulkUpdate">stopBulkUpdate</a>
|
752
|
+
* <a href="#is_changed">is_changed</a>
|
720
753
|
|
721
754
|
### <a id="name"></a>name property
|
722
755
|
|
@@ -924,6 +957,13 @@ Run this method when you start to create or update a bunch of models; it will op
|
|
924
957
|
:::cplusplus
|
925
958
|
- (void) stopBulkUpdate;
|
926
959
|
|
960
|
+
### <a id="is_changed">is_changed
|
961
|
+
|
962
|
+
Check does model contain non-synced local changes
|
963
|
+
|
964
|
+
:::cplusplus
|
965
|
+
- (BOOL) is_changed;
|
966
|
+
|
927
967
|
## RhoConnectNotify Class API
|
928
968
|
|
929
969
|
Several RhoConnectClient methods return a RhoConnectNotify object. The properties for the RhoConnectNotify class provide access to sync notification objects as described [here](/rhodes/synchronization#notifications). (Developers do not set RhoConnectNotify properties, but only read them after a call to a RhoConnectClient method that returns a RhoConnectNotify object.)
|
data/doc/client.txt
CHANGED
@@ -43,6 +43,9 @@ Rhoconnect Client is a library to add sync data capability to your applications.
|
|
43
43
|
//default is 0. Not supported yet
|
44
44
|
@property(setter=setPollInterval) int poll_interval;
|
45
45
|
|
46
|
+
//default is 0. Set minimal severity level for messages to log output
|
47
|
+
@property(setter=setLogSeverity) int log_severity;
|
48
|
+
|
46
49
|
//set rhoconnect server url, for example: "http://<ip>:<port>/application"
|
47
50
|
@property(assign, setter=setSyncServer) NSString* sync_server;
|
48
51
|
|
@@ -74,6 +77,12 @@ Rhoconnect Client is a library to add sync data capability to your applications.
|
|
74
77
|
// run sync of all models
|
75
78
|
- (RhoConnectNotify*) syncAll;
|
76
79
|
|
80
|
+
// check is sync is in progress
|
81
|
+
- (BOOL) is_syncing;
|
82
|
+
|
83
|
+
//stop current sync if running
|
84
|
+
- (void) stop_sync;
|
85
|
+
|
77
86
|
//send search request to rhoconnect
|
78
87
|
- (RhoConnectNotify*) search: (NSArray*)models from: (NSString*) from params: (NSString*)params sync_changes: (BOOL)
|
79
88
|
sync_changes progress_step: (int) progress_step;
|
@@ -148,6 +157,9 @@ Rhoconnect Client is a library to add sync data capability to your applications.
|
|
148
157
|
//these are equivalent to start/commit transaction
|
149
158
|
- (void) startBulkUpdate;
|
150
159
|
- (void) stopBulkUpdate;
|
160
|
+
|
161
|
+
//check does model was modified and not yet synced
|
162
|
+
- (BOOL) is_changed;
|
151
163
|
|
152
164
|
#### RhoConnectNotify
|
153
165
|
|
data/doc/command-line.txt
CHANGED
@@ -61,7 +61,9 @@ After generating the application, you might be asked to change directories to yo
|
|
61
61
|
|
62
62
|
### Add a New Source Adapter
|
63
63
|
|
64
|
-
To generate a source for your RhoConnect application, run the `rhoconnect source` command within your application directory
|
64
|
+
To generate a source for your RhoConnect application, you can run the `rhoconnect source` command within your application directory.
|
65
|
+
|
66
|
+
**NOTE:** You can also write the source into your backend application and [write a RhoConnect plugin](/rhoconnect/plugin-intro) in Java, .NET, or other language for that application.
|
65
67
|
|
66
68
|
:::term
|
67
69
|
Usage: rhoconnect source name [options] [args]
|
@@ -69,7 +71,7 @@ To generate a source for your RhoConnect application, run the `rhoconnect source
|
|
69
71
|
Generates a new source adapter.
|
70
72
|
|
71
73
|
Required:
|
72
|
-
name - source name(i.e. product)
|
74
|
+
name - the source name(i.e. product)
|
73
75
|
|
74
76
|
|
75
77
|
Options specific for this generator:
|
@@ -215,4 +217,11 @@ Here is a complete list of the rake tasks available in a RhoConnect application:
|
|
215
217
|
rake rhoconnect:start # Start rhoconnect server
|
216
218
|
rake rhoconnect:stop # Stop rhoconnect server
|
217
219
|
rake rhoconnect:war # Build executable WAR file to be used in Java App Servers
|
218
|
-
rake rhoconnect:web # Launch the web console in a browser - uses :syncserver: in settings.yml
|
220
|
+
rake rhoconnect:web # Launch the web console in a browser - uses :syncserver: in settings.yml
|
221
|
+
|
222
|
+
## Generate Source
|
223
|
+
|
224
|
+
Connecting to a backend service with RhoConnect requires that you write a small amount of code for the query, create, update and delete operations of your particular enterprise backend. The collection of the code for these operations is called a source. To generate source for your RhoConnect application:
|
225
|
+
|
226
|
+
* Generate a Ruby code [RhoConnect source adapter](/rhoconnect/source-adapters).
|
227
|
+
* Write the source code (the query, create, update and delete operations) into your backend application and [write a RhoConnect plugin](/rhoconnect/plugin-intro) in the language that matchs your backend application, such as Java or .NET.
|
@@ -0,0 +1,68 @@
|
|
1
|
+
Resolving CUD conflicts
|
2
|
+
===
|
3
|
+
|
4
|
+
Rhoconnect CUD queue and potential conflicts
|
5
|
+
---
|
6
|
+
|
7
|
+
By design, your Rhoconnect application supports parallel dispatching of the multiple client's requests via the asynchronous Resque jobs. This scenario can lead to a situation where two or more clients will try to perform CUD operations at the same time, potentially creating the race condition. For example, this can happen when two users will try to insert or delete the same record simultaneously.
|
8
|
+
To handle this situation , Rhoconnect uses the CUD queue, which is being dispatched continuously. You can inspect this queue before the CUD operation is called and mark the conflicting records for special processing. To do this, you need to override the Source Adapter `validate` method that is called before the CUD queue is dispatched. This method has the following parameters:
|
9
|
+
|
10
|
+
<table border="1">
|
11
|
+
<tr>
|
12
|
+
<td>String</td>
|
13
|
+
<td><code>operation</code></td>
|
14
|
+
<td>CUD operation marker, one of three: create, update, or delete</td>
|
15
|
+
</tr>
|
16
|
+
<tr>
|
17
|
+
<td>Array Of Record Hashes</td>
|
18
|
+
<td><code>cud_queue</code></td>
|
19
|
+
<td>CUD queue consisting of CUD request hashes, ordered from oldest to newest. Each entry in the queue contains a hash of CUD records to process. (Each CUD client request can contain more than one record</td>
|
20
|
+
</tr>
|
21
|
+
<tr>
|
22
|
+
<td>Array Of Client Ids</td>
|
23
|
+
<td><code>client_queue</code></td>
|
24
|
+
<td>This array is used to map the CUD request in the above queue to a corresponding client ID. i.e. CUD_queue[N] request was issued by client_queue[N] client. Please note that there may be several entries from the same client - if they came separately in time</td>
|
25
|
+
</tr>
|
26
|
+
</table>
|
27
|
+
|
28
|
+
Below you can see the example of the `validate` method parameters indicating two create requests containing the conflicting records:
|
29
|
+
|
30
|
+
:::ruby
|
31
|
+
client_1 = 'cid_1'
|
32
|
+
cud_request_1 = { 'temp_cid1_1' => {'name' => 'iPhone'}, 'temp_cid1_2' => {'name' => 'Android'}}
|
33
|
+
client_2 = 'cid_2'
|
34
|
+
cud_request_2 = { 'temp_cid2_1' => {'name' => 'iPhone'}} # this record seems to be the duplicate of the record 'temp_cid1_1'
|
35
|
+
|
36
|
+
operation = 'create'
|
37
|
+
cud_queue = [ cud_request_1, cud_request_2 ]
|
38
|
+
client_ids = [ client_1, client_2 ]
|
39
|
+
|
40
|
+
Detecting the conflict and forcing an error
|
41
|
+
---
|
42
|
+
|
43
|
+
Using the above `validate` method you can iterate through the queue and detect CUD conflicts based on the desired application logic. Once the conflicting record is found (for example, duplicate create request), you need to mark it by inserting the conflicting record parameters into the special hash structure that is returned by the `validate` method:
|
44
|
+
|
45
|
+
:::ruby
|
46
|
+
def validate(operation, cud_queue, client_ids)
|
47
|
+
resulting_meta_hash = {}
|
48
|
+
|
49
|
+
# iterating through the queue
|
50
|
+
cud_queue.each_with_index do |cud_request, index|
|
51
|
+
cud_request_client = client_ids[index]
|
52
|
+
|
53
|
+
# iterating through the request records
|
54
|
+
cud_request.each do |record_id, record_hash|
|
55
|
+
# ... detecting the conflict here ....
|
56
|
+
# !!! found a conflict - force an error
|
57
|
+
error_record_id = record_id
|
58
|
+
record_meta_data = { error_record_id => { :error => 'my_error_string: conflict is detected!!!' }}
|
59
|
+
resulting_meta_hash[index] ||= {}
|
60
|
+
resulting_meta_hash[index].merge!(record_meta_data)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
resulting_meta_hash
|
65
|
+
end
|
66
|
+
|
67
|
+
Once the `validate` method returns non-empty validation metadata hash structure, it will be used in processing the CUD queue. All marked records will not be processed, but instead an error will be sent back to the originating client with the user-provided error message.
|
68
|
+
|