rhoconnect 3.0.5 → 3.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +7 -1
- data/Gemfile.lock +9 -9
- data/README.md +4 -4
- data/Rakefile +41 -28
- data/bench/bench_runner.rb +4 -5
- data/bench/benchapp/Gemfile +1 -1
- data/bench/benchapp/Gemfile.lock +26 -27
- data/bench/benchapp/config.ru +4 -0
- data/bench/benchapp/log/passenger.3000.log +1 -0
- data/bench/benchapp/log/passenger.9292.log +59 -0
- data/bench/benchapp/settings/settings.yml +2 -0
- data/bench/benchapp/tmp/pids/passenger.3000.pid.lock +0 -0
- data/bench/benchapp/tmp/pids/passenger.9292.pid.lock +0 -0
- data/bench/distr_bench/distr_bench +7 -0
- data/bench/distr_bench/distr_bench_main +99 -0
- data/bench/distr_bench/run_distr_client.sh +12 -0
- data/bench/distr_bench/run_test_query_script.sh +50 -0
- data/bench/lib/bench/bench_result_processor.rb +90 -0
- data/bench/lib/bench/cli.rb +35 -2
- data/bench/lib/bench/logging.rb +2 -0
- data/bench/lib/bench/runner.rb +4 -2
- data/bench/lib/bench/session.rb +3 -1
- data/bench/lib/bench/statistics.rb +41 -1
- data/bench/lib/bench/timer.rb +7 -0
- data/bench/lib/bench/utils.rb +8 -0
- data/bench/lib/bench.rb +35 -9
- 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 +15 -0
- data/bench/lib/testdata/2-data.txt +3 -0
- data/bench/lib/testdata/25-data.txt +39 -0
- data/bench/lib/testdata/250-data.txt +353 -0
- data/bench/lib/testdata/3-data.txt +4 -0
- data/bench/lib/testdata/5-data.txt +7 -8
- data/bench/lib/testdata/50-data.txt +70 -0
- data/bench/lib/testdata/500-data.txt +711 -0
- data/bench/prepare_bench +45 -0
- data/bench/run_bench.sh +3 -3
- data/bench/run_blob_script.sh +1 -1
- data/bench/run_cud_script.sh +1 -1
- data/bench/run_query_md_script.sh +1 -1
- data/bench/run_query_only_script.sh +1 -1
- data/bench/run_query_script.sh +1 -1
- data/bench/run_test_query_script.sh +30 -0
- data/bench/run_test_source_script.sh +21 -0
- data/bench/scripts/test_query_script.rb +64 -0
- data/bench/scripts/test_source_script.rb +27 -0
- data/bin/rhoconnect-benchmark +13 -0
- data/doc/client-objc.txt +236 -1
- data/doc/client.txt +132 -0
- data/doc/extending-rhoconnect-server.txt +79 -0
- data/doc/install.txt +1 -1
- data/doc/java-plugin.txt +291 -0
- data/doc/rest-api.txt +3 -1
- data/installer/unix-like/create_texts.rb +73 -16
- data/installer/unix-like/pre_install.sh +1 -1
- data/installer/unix-like/rho_connect_install_constants.rb +1 -1
- data/installer/utils/constants.rb +2 -2
- data/installer/utils/nix_install_test.rb +85 -75
- data/installer/utils/package_upload/repos.rake +82 -2
- data/installer/windows/rhosync.nsi +5 -5
- data/lib/rhoconnect/api/application/queue_updates.rb +14 -0
- data/lib/rhoconnect/api/source/set_db_doc.rb +3 -1
- data/lib/rhoconnect/server.rb +9 -17
- data/lib/rhoconnect/version.rb +1 -1
- data/rhoconnect.gemspec +1 -1
- data/spec/api/admin/get_api_token_spec.rb +6 -0
- data/spec/api/source/set_db_doc_spec.rb +13 -0
- data/spec/server/server_spec.rb +27 -1
- data/tasks/redis.rake +2 -2
- metadata +73 -48
- data/examples/simple/dump.rdb +0 -0
- data/installer/utils/package_upload/repos.rb +0 -83
data/doc/client.txt
CHANGED
|
@@ -83,6 +83,20 @@ Rhoconnect Client is a library to add sync data capability to your applications.
|
|
|
83
83
|
- (void) clearObjectNotification;
|
|
84
84
|
//add object to track changes: create, update, delete
|
|
85
85
|
- (void) addObjectNotify: (int) nSrcID szObject:(NSString*) szObject;
|
|
86
|
+
|
|
87
|
+
//To process 'create-error' errors from server:
|
|
88
|
+
//Action may be "delete" or "recreate"
|
|
89
|
+
//"delete" just remove object from client, "recreate" will push this object to server again at next sync.
|
|
90
|
+
- (void) onCreateError: (RhoConnectNotify*)notify action: (NSString*)action;
|
|
91
|
+
|
|
92
|
+
//To process 'update-error' errors from server:
|
|
93
|
+
//Action may be "retry" or "rollback".
|
|
94
|
+
//"retry" will push update object operation to server again at next sync, "rollback" will write rollback objects(comes from server) to client database.
|
|
95
|
+
- (void) onUpdateError: (RhoConnectNotify*)notify action: (NSString*)action;
|
|
96
|
+
|
|
97
|
+
//To process 'delete-error' errors from server:
|
|
98
|
+
//Action may be "retry" - will push delete object operation to server again at next sync.
|
|
99
|
+
- (void) onDeleteError: (RhoConnectNotify*)notify action: (NSString*)action;
|
|
86
100
|
|
|
87
101
|
#### RhomModel
|
|
88
102
|
|
|
@@ -151,6 +165,11 @@ This class provides access to sync notification objects as describe [here](/rhod
|
|
|
151
165
|
@property(assign) NSString* error_message;
|
|
152
166
|
@property(assign) NSString* callback_params;
|
|
153
167
|
|
|
168
|
+
- (Boolean) hasCreateErrors;
|
|
169
|
+
- (Boolean) hasUpdateErrors;
|
|
170
|
+
- (Boolean) hasDeleteErrors;
|
|
171
|
+
- (Boolean) isUnknownClientError;
|
|
172
|
+
|
|
154
173
|
#### RhoConnectObjectNotify
|
|
155
174
|
|
|
156
175
|
This class provides access to sync object notification as describe [here](/rhodes/synchronization#notifications):
|
|
@@ -192,6 +211,7 @@ See [rhoconnect-client\Samples\ObjectiveC\store](http://github.com/rhomobile/rho
|
|
|
192
211
|
|
|
193
212
|
#### Initialization of Schema model
|
|
194
213
|
|
|
214
|
+
:::cplusplus
|
|
195
215
|
RhomModel* product = [[RhomModel alloc] init];
|
|
196
216
|
product.name = @"Product_s";
|
|
197
217
|
product.model_type = RMT_PROPERTY_FIXEDSCHEMA;
|
|
@@ -203,9 +223,13 @@ To create schema model tables edit database schema file:
|
|
|
203
223
|
* Edit file syncdb.schema : add create table statment for each schema model. Note that mandatory object column should be in each table:
|
|
204
224
|
|
|
205
225
|
"object" varchar(255) PRIMARY KEY
|
|
226
|
+
|
|
227
|
+
** NOTE: Do not use NOT NULL statement in column definitions. RhoConnect client delete object attributes by setting value to null, when all object attributes become nulls, object deleted. So objects with NOT NULL columns will not be deleted. **
|
|
228
|
+
|
|
206
229
|
|
|
207
230
|
* Open 'Copy bundle resources' build phase in project target and point it to local project db folder
|
|
208
231
|
|
|
232
|
+
|
|
209
233
|
#### Login
|
|
210
234
|
|
|
211
235
|
:::cplusplus
|
|
@@ -241,6 +265,114 @@ To create schema model tables edit database schema file:
|
|
|
241
265
|
|
|
242
266
|
[sclient addObjectNotify: [[item objectForKey:@"source_id"] intValue] szObject:[item valueForKey:@"object"] ];
|
|
243
267
|
|
|
268
|
+
#### Processing unknown-client error
|
|
269
|
+
Unknown client error return by server after resetting server database, removing particular client id from database or any other cases when server cannot find client id(sync server unique id of device).
|
|
270
|
+
Note that login session may still exist on server, so in this case client does not have to login again, just create new client id.
|
|
271
|
+
Processing of this error contain 2 steps:
|
|
272
|
+
|
|
273
|
+
* When unknown client error is come from server, client should call database_client_reset and start new sync, to register new client id.
|
|
274
|
+
|
|
275
|
+
* If login session also deleted or expired on the server, then customer has to login again.
|
|
276
|
+
|
|
277
|
+
Example:
|
|
278
|
+
:::cplusplus
|
|
279
|
+
|
|
280
|
+
- (void)syncAllCalback:(RhoConnectNotify*) notify
|
|
281
|
+
{
|
|
282
|
+
NSString* status = notify.status;
|
|
283
|
+
NSString* error = notify.error_message;
|
|
284
|
+
int err_code = notify.error_code;
|
|
285
|
+
|
|
286
|
+
NSLog(@"syncAll DONE, status: '%s' , error_msg: '%s' , error_code: %d",
|
|
287
|
+
[status cStringUsingEncoding: NSUTF8StringEncoding],
|
|
288
|
+
[error cStringUsingEncoding: NSUTF8StringEncoding],
|
|
289
|
+
err_code
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
if ( [notify.status compare:@"in_progress"] == 0) {
|
|
293
|
+
|
|
294
|
+
} else if ([notify.status compare:@"complete"] == 0) {
|
|
295
|
+
|
|
296
|
+
[[RhoConnectEngine sharedInstance].syncClient clearNotification];
|
|
297
|
+
|
|
298
|
+
} else if ([notify.status compare:@"error"] == 0) {
|
|
299
|
+
|
|
300
|
+
if([notify isUnknownClientError]) {
|
|
301
|
+
[[RhoConnectEngine sharedInstance].syncClient database_client_reset];
|
|
302
|
+
[[RhoConnectEngine sharedInstance].syncClient setNotification: @selector(syncAllCalback:) target:self];
|
|
303
|
+
[[RhoConnectEngine sharedInstance].syncClient syncAll];
|
|
304
|
+
} else if( err_code == RHO_ERR_CLIENTISNOTLOGGEDIN
|
|
305
|
+
|| err_code == RHO_ERR_UNATHORIZED) {
|
|
306
|
+
|
|
307
|
+
NSLog(@"GO TO LOGIN PAGE!");
|
|
308
|
+
// real code to trigger view transition goes here..
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
#### Processing server errors
|
|
314
|
+
* create-error:
|
|
315
|
+
has to be handled in sync callback. Otherwise sync will stop on this model. To fix create errors you should call Model.on_sync_create_error or SyncEngine.on_sync_create_error:
|
|
316
|
+
|
|
317
|
+
* update-error:
|
|
318
|
+
If not handled, local modifications, which were failing on server, will never sync to server again.
|
|
319
|
+
So sync will work fine, but nobody will know about these changes.
|
|
320
|
+
|
|
321
|
+
* delete-error:
|
|
322
|
+
If not handled, local modifications, which were failing on server, will never sync to server again.
|
|
323
|
+
So sync will work fine, but nobody will know about these changes.
|
|
324
|
+
|
|
325
|
+
Example:
|
|
326
|
+
:::cplusplus
|
|
327
|
+
|
|
328
|
+
- (void)syncAllCalback:(RhoConnectNotify*) notify
|
|
329
|
+
{
|
|
330
|
+
NSString* status = notify.status;
|
|
331
|
+
NSString* error = notify.error_message;
|
|
332
|
+
int err_code = notify.error_code;
|
|
333
|
+
|
|
334
|
+
NSLog(@"syncAll DONE, status: '%s' , error_msg: '%s' , error_code: %d",
|
|
335
|
+
[status cStringUsingEncoding: NSUTF8StringEncoding],
|
|
336
|
+
[error cStringUsingEncoding: NSUTF8StringEncoding],
|
|
337
|
+
err_code
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
if ( [notify.status compare:@"in_progress"] == 0) {
|
|
341
|
+
|
|
342
|
+
} else if ([notify.status compare:@"complete"] == 0) {
|
|
343
|
+
|
|
344
|
+
[[RhoConnectEngine sharedInstance].syncClient clearNotification];
|
|
345
|
+
|
|
346
|
+
} else if ([notify.status compare:@"error"] == 0) {
|
|
347
|
+
|
|
348
|
+
if([notify isUnknownClientError]) {
|
|
349
|
+
[[RhoConnectEngine sharedInstance].syncClient database_client_reset];
|
|
350
|
+
[[RhoConnectEngine sharedInstance].syncClient setNotification: @selector(syncAllCalback:) target:self];
|
|
351
|
+
[[RhoConnectEngine sharedInstance].syncClient syncAll];
|
|
352
|
+
} else if( err_code == RHO_ERR_CLIENTISNOTLOGGEDIN
|
|
353
|
+
|| err_code == RHO_ERR_UNATHORIZED) {
|
|
354
|
+
|
|
355
|
+
NSLog(@"GO TO LOGIN PAGE!");
|
|
356
|
+
// real code to trigger view transition goes here..
|
|
357
|
+
}else
|
|
358
|
+
{
|
|
359
|
+
//This is mandatory:
|
|
360
|
+
if([notify hasCreateErrors]) {
|
|
361
|
+
[[RhoConnectEngine sharedInstance].syncClient onCreateError: notify action:@"delete"];
|
|
362
|
+
}
|
|
363
|
+
//These are optional:
|
|
364
|
+
/*
|
|
365
|
+
if([notify hasUpdateErrors]) {
|
|
366
|
+
[[RhoConnectEngine sharedInstance].syncClient onUpdateError: notify action:@"rollback"];
|
|
367
|
+
}
|
|
368
|
+
if([notify hasDeleteErrors]) {
|
|
369
|
+
[[RhoConnectEngine sharedInstance].syncClient onDeleteError: notify action:@"retry"];
|
|
370
|
+
}
|
|
371
|
+
*/
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
244
376
|
#### Run SQL query on Schema model
|
|
245
377
|
|
|
246
378
|
:::cplusplus
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
Extending Rhoconnect Application with custom routes
|
|
2
|
+
===
|
|
3
|
+
|
|
4
|
+
Extending Rhoconnect Application with custom routes
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You can provide custom routes support in your Rhoconnect application while you still fully utilize the powerful features provided by the default Rhoconnect server implementation. To do this, create a custom server class inherited from `Rhoconnect::Server` and define all of your custom routes in this extended server class.
|
|
8
|
+
|
|
9
|
+
The following example illustrates how to add a sample `my_custom_route' to the existing Rhoconnect application.
|
|
10
|
+
|
|
11
|
+
1) create `my_server.rb` class in your Rhoconnect application's root directory:
|
|
12
|
+
|
|
13
|
+
:::ruby
|
|
14
|
+
class MyServer < Rhoconnect::Server
|
|
15
|
+
get '/my_custom_route' do
|
|
16
|
+
if current_user
|
|
17
|
+
send_file 'public/my_file.png'
|
|
18
|
+
end
|
|
19
|
+
nil
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
The above custom route implementation will respond to client's GET request, verifies the current_user (which will be extracted from the Rhoconnect session cookie)
|
|
24
|
+
and returns a static PNG file (which can be later used in BLOB syncs)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
2) Replace the default server instance with the new extended one in the `config.ru` file of your Rhoconnect application:
|
|
28
|
+
|
|
29
|
+
:::ruby
|
|
30
|
+
# Setup the url map
|
|
31
|
+
run Rack::URLMap.new \
|
|
32
|
+
"/" => MyServer.new,
|
|
33
|
+
"/resque" => Resque::Server.new, # If you don't want resque frontend, disable it here
|
|
34
|
+
"/console" => RhoconnectConsole::Server.new # If you don't want rhoconnect frontend, disable it here
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
Using the New Custom route in BLOB syncs
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
After you create the new custom routes and replace the default server instance with the new extended one, you can reference and use them from standard Rhodes applications.
|
|
41
|
+
For example, suppose you have a Rhodes app with a Product model. To use a custom route in BLOB syncs, define the following property in the Rhodes Product model (file: `app/Product/product.rb`):
|
|
42
|
+
|
|
43
|
+
:::ruby
|
|
44
|
+
# The model has already been created by the framework, and extends Rhom::RhomObject
|
|
45
|
+
# You can add more methods here
|
|
46
|
+
class Product
|
|
47
|
+
include Rhom::PropertyBag
|
|
48
|
+
|
|
49
|
+
# Uncomment the following line to enable sync with Product.
|
|
50
|
+
enable :sync
|
|
51
|
+
|
|
52
|
+
#add model specifc code here
|
|
53
|
+
property :my_custom_blob_field, :blob, :overwrite
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
To see the static image, modify the `app/Product/show.erb` file for the Product model in your Rhodes application:
|
|
57
|
+
|
|
58
|
+
:::html
|
|
59
|
+
<li>
|
|
60
|
+
<div class="itemLabel">My Static Field Image</div>
|
|
61
|
+
<div class="itemValue"><img src="<%=Rho::RhoApplication::get_blob_path(@product.my_custom_field)%>"></img></div>
|
|
62
|
+
</li>
|
|
63
|
+
|
|
64
|
+
Then, modify your Rhoconnect source adapter (in `rhoconnect_app/sources/product.rb`) to provide BLOB's url for the `my_custom_blob_field`:
|
|
65
|
+
|
|
66
|
+
:::ruby
|
|
67
|
+
def query(params=nil)
|
|
68
|
+
parsed = JSON.parse(RestClient.get("#{@base}.json").body)
|
|
69
|
+
|
|
70
|
+
@result={}
|
|
71
|
+
parsed.each do |item|
|
|
72
|
+
item["product"]["my_custom_field-rhoblob"] = "http://localhost:9292/my_custom_route"
|
|
73
|
+
@result[item["product"]["id"].to_s] = item["product"]
|
|
74
|
+
end if parsed
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
This way, your `my_custom_field` would be getting the BLOB image data from the custom route defined in your Rhoconnect extension server.
|
|
78
|
+
|
|
79
|
+
For more information on BLOB syncs, see [this section](http://docs.rhomobile.com/rhoconnect/blob-sync).
|
data/doc/install.txt
CHANGED
|
@@ -17,7 +17,7 @@ You can now skip to the [generating a new application instructions](/rhoconnect/
|
|
|
17
17
|
|
|
18
18
|
3. Ruby Web Server - We test with [thin](http://code.macournoyer.com/thin/), and [passenger](http://www.modrails.com/). WEBrick, the web server that ships with ruby, is known to cause issues with HTTP headers/cookies and is ***not*** recommended.
|
|
19
19
|
|
|
20
|
-
4. [Redis 2.4.
|
|
20
|
+
4. [Redis 2.4.x](http://redis.io/) - RhoConnect includes a simple [rake task](/rhoconnect/command-line#rake-tasks) `redis:install` to install redis, covered in the [Rake Tasks section](/rhoconnect/command-line#rake-tasks). Alternatively, you can [install redis directly](http://redis.io/download).
|
|
21
21
|
|
|
22
22
|
### Installing RhoConnect Gem
|
|
23
23
|
|
data/doc/java-plugin.txt
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
RhoConnect-Java
|
|
2
|
+
===
|
|
3
|
+
|
|
4
|
+
RhoConnect-Java library is designed for the [RhoConnect](http://rhomobile.com/products/rhoconnect/) App Integration Server.
|
|
5
|
+
|
|
6
|
+
Using the RhoConnect-Java plugin, your [Spting 3 MVC](http://www.springsource.org/) application's data will transparently synchronize with a mobile application built on the [Rhodes framework](http://rhomobile.com/products/rhodes), or any of the available [RhoConnect clients](http://rhomobile.com/products/rhoconnect/).
|
|
7
|
+
|
|
8
|
+
## Getting started
|
|
9
|
+
|
|
10
|
+
We assume that you have a complete java end-to-end application using Spring 3.0 MVC as the front end technology and Hibernate as backend ORM. For this application we will also use Maven2 for build and dependency management and some database to persist the data. The database is accessed by a Data Access (DAO) layer.
|
|
11
|
+
|
|
12
|
+
For testing and evaluation purposes you can use [RhoconnectJavaSample](https://github.com/shurab/RhoconnectJavaSample) application as a starting point before continuing with the following steps.
|
|
13
|
+
|
|
14
|
+
### Adding Dependencies to Your Maven 2 Project
|
|
15
|
+
|
|
16
|
+
Add dependencies to your Apache Maven 2 project object model (POM): apache common beanutils, and Jackson JSON mapper. In the RhoconnectJavaSample application, this code is in the pom.xml file.
|
|
17
|
+
|
|
18
|
+
:::xml
|
|
19
|
+
<!-- apache commons beanutils -->
|
|
20
|
+
<dependency>
|
|
21
|
+
<groupId>commons-beanutils</groupId>
|
|
22
|
+
<artifactId>commons-beanutils</artifactId>
|
|
23
|
+
<version>1.8.3</version>
|
|
24
|
+
</dependency>
|
|
25
|
+
<!-- Jackson JSON Mapper -->
|
|
26
|
+
<dependency>
|
|
27
|
+
<groupId>org.codehaus.jackson</groupId>
|
|
28
|
+
<artifactId>jackson-mapper-asl</artifactId>
|
|
29
|
+
<version>1.9.0</version>
|
|
30
|
+
<type>jar</type>
|
|
31
|
+
<optional>false</optional>
|
|
32
|
+
</dependency>
|
|
33
|
+
|
|
34
|
+
### Updating Your Servlet XML Configuration File
|
|
35
|
+
|
|
36
|
+
Update your servlet xml configuration file to include rhoconnect-java metadata: the packages, converters, and beans. In the RhoconnectJavaSample, this code is in comments in the src/main/webapp/WEB-INF/spring-servlet.xml file.
|
|
37
|
+
|
|
38
|
+
:::xml
|
|
39
|
+
<!-- rhoconnect-java plugin packages -->
|
|
40
|
+
<context:component-scan base-package="com.rhomobile.rhoconnect.controller" />
|
|
41
|
+
|
|
42
|
+
<!-- rhoconnect-java plugin converters -->
|
|
43
|
+
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
|
|
44
|
+
<property name="order" value="1" />
|
|
45
|
+
<property name="messageConverters">
|
|
46
|
+
<list>
|
|
47
|
+
<ref bean="stringHttpMessageConverter"/>
|
|
48
|
+
<ref bean="jsonConverter" />
|
|
49
|
+
</list>
|
|
50
|
+
</property>
|
|
51
|
+
</bean>
|
|
52
|
+
|
|
53
|
+
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
|
|
54
|
+
<property name="supportedMediaTypes" value="application/json" />
|
|
55
|
+
</bean>
|
|
56
|
+
|
|
57
|
+
<bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter">
|
|
58
|
+
</bean>
|
|
59
|
+
|
|
60
|
+
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
|
|
61
|
+
<property name="messageConverters">
|
|
62
|
+
<list>
|
|
63
|
+
<ref bean="jsonConverter" />
|
|
64
|
+
<ref bean="stringHttpMessageConverter"/>
|
|
65
|
+
</list>
|
|
66
|
+
</property>
|
|
67
|
+
</bean>
|
|
68
|
+
|
|
69
|
+
<!-- rhoconnect-java plugin beans -->
|
|
70
|
+
<bean id="rhoconnect" class = "com.rhomobile.rhoconnect.RhoconnectImpl" />
|
|
71
|
+
|
|
72
|
+
<bean id="rhoconnectClient" class = "com.rhomobile.rhoconnect.RhoconnectClient" init-method="setAppEndpoint" >
|
|
73
|
+
<property name="restTemplate"><ref bean="restTemplate"/></property>
|
|
74
|
+
<property name="endpointUrl" value="your_rhoconnect_server_url" />
|
|
75
|
+
<property name="appEndpoint" value="your_spring_app_url" />
|
|
76
|
+
<property name="apiToken" value="rhoconnect_api_token" />
|
|
77
|
+
</bean>
|
|
78
|
+
|
|
79
|
+
The `setAppEndpoint` method in the `rhoconnectClient` bean in the above code sample is a main point in establishing the communication
|
|
80
|
+
link between the `Rhoconnect` server and the Spring 3 MVC application. It has the following properties that you need to configure.
|
|
81
|
+
|
|
82
|
+
<table border="1">
|
|
83
|
+
<tr>
|
|
84
|
+
<td><code>endpointUrl</code></td>
|
|
85
|
+
<td>rhoconnect server's url, for example <code>http://localhost:9292</code>.</td>
|
|
86
|
+
</tr>
|
|
87
|
+
<tr>
|
|
88
|
+
<td><code>appEndpoint</code></td>
|
|
89
|
+
<td>your Spring 3 MVC app url, for example <code>http://localhost:8080/contacts</code>.</td>
|
|
90
|
+
</tr>
|
|
91
|
+
<tr>
|
|
92
|
+
<td><code>apiToken</code></td>
|
|
93
|
+
<td>rhoconnect server's api_token, for example <code>sometokenforme</code>.</td>
|
|
94
|
+
</tr>
|
|
95
|
+
</table>
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
### Adding rhoconnect-java to the Build Path
|
|
99
|
+
|
|
100
|
+
You must add the rhoconnect-java jar to your apache maven 2 build classpath. In the RhoconnectJavaSample application, you would add this code to the pom.xml file, putting in the path to your rhoconnect-java jar into the systemPath.
|
|
101
|
+
|
|
102
|
+
:::xml
|
|
103
|
+
<dependency>
|
|
104
|
+
<groupId>rhoconnect-java</groupId>
|
|
105
|
+
<artifactId>rhoconnect-java</artifactId>
|
|
106
|
+
<version>0.0.1</version>
|
|
107
|
+
<scope>system</scope>
|
|
108
|
+
<!-- Set absolute path to your rhoconnect-java jar -->
|
|
109
|
+
<systemPath>/path-to-jar-directory/rhoconnect-java-0.0.1.jar</systemPath>
|
|
110
|
+
</dependency>
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
### Establishing communication from the RhoConnect server to java back-end application
|
|
114
|
+
|
|
115
|
+
You need to establish communication from the RhoConnect instance to your java back-end application by implementing Rhoconnect interface.
|
|
116
|
+
|
|
117
|
+
:::java
|
|
118
|
+
package com.rhomobile.rhoconnect;
|
|
119
|
+
import java.util.Map;
|
|
120
|
+
|
|
121
|
+
public interface Rhoconnect {
|
|
122
|
+
boolean authenticate(String login, String password, Map<String, Object> attribures);
|
|
123
|
+
|
|
124
|
+
Map<String, Object> query_objects(String resource, String partition);
|
|
125
|
+
Integer create(String resource, String partition, Map<String, Object> attributes);
|
|
126
|
+
Integer update(String resource, String partition, Map<String, Object> attributes);
|
|
127
|
+
Integer delete(String resource, String partition, Map<String, Object> attributes);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
For example, `RhoconnectJavaSample` application implementation is based on `contactService` API:
|
|
131
|
+
|
|
132
|
+
:::java
|
|
133
|
+
/**
|
|
134
|
+
* RhoconnectImpl.java
|
|
135
|
+
*/
|
|
136
|
+
package com.rhomobile.rhoconnect;
|
|
137
|
+
|
|
138
|
+
import java.util.HashMap;
|
|
139
|
+
import java.util.Iterator;
|
|
140
|
+
import java.util.List;
|
|
141
|
+
import java.util.Map;
|
|
142
|
+
|
|
143
|
+
import org.apache.commons.beanutils.BeanUtils;
|
|
144
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
145
|
+
|
|
146
|
+
import com.rhomobile.contact.form.Contact;
|
|
147
|
+
import com.rhomobile.contact.service.ContactService;
|
|
148
|
+
|
|
149
|
+
public class RhoconnectImpl implements Rhoconnect {
|
|
150
|
+
|
|
151
|
+
@Autowired
|
|
152
|
+
private ContactService contactService;
|
|
153
|
+
|
|
154
|
+
@Override
|
|
155
|
+
public boolean authenticate(String login, String password, Map<String, Object> attribures) {
|
|
156
|
+
// TODO: your authentication code goes here ...
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@Override
|
|
161
|
+
public Map<String, Object> query_objects(String resource, String partition) {
|
|
162
|
+
Map<String, Object> h = new HashMap<String, Object>();
|
|
163
|
+
List<Contact> contacts = contactService.listContact();
|
|
164
|
+
Iterator<Contact> it = contacts.iterator( );
|
|
165
|
+
while(it.hasNext()) {
|
|
166
|
+
Contact c =(Contact)it.next();
|
|
167
|
+
h.put(c.getId().toString(), c);
|
|
168
|
+
}
|
|
169
|
+
return h;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
@Override
|
|
173
|
+
public Integer create(String resource, String partition, Map<String, Object> attributes) {
|
|
174
|
+
Contact contact = new Contact();
|
|
175
|
+
try {
|
|
176
|
+
BeanUtils.populate(contact, attributes);
|
|
177
|
+
int id = contactService.addContact(contact);
|
|
178
|
+
return id;
|
|
179
|
+
} catch(Exception e) {
|
|
180
|
+
e.printStackTrace();
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@Override
|
|
186
|
+
public Integer update(String resource, String partition, Map<String, Object> attributes) {
|
|
187
|
+
Integer id = Integer.parseInt((String)attributes.get("id"));
|
|
188
|
+
Contact contact = contactService.getContact(id);
|
|
189
|
+
try {
|
|
190
|
+
BeanUtils.populate(contact, attributes);
|
|
191
|
+
contactService.updateContact(contact);
|
|
192
|
+
return id;
|
|
193
|
+
} catch(Exception e) {
|
|
194
|
+
e.printStackTrace();
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
@Override
|
|
200
|
+
public Integer delete(String resource, String partition, Map<String, Object> attributes) {
|
|
201
|
+
String objId = (String)attributes.get("id");
|
|
202
|
+
Integer id = Integer.parseInt(objId);
|
|
203
|
+
contactService.removeContact(id);
|
|
204
|
+
return id;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
### Establishing communication from java back-end application to the RhoConnect server
|
|
209
|
+
|
|
210
|
+
You also must to establish the communication from your java back-end application to the RhoConnect instance by autowiring your data access (DAO) service layer with RhoconnectClient bean and inserting notifications hooks there.
|
|
211
|
+
|
|
212
|
+
:::java
|
|
213
|
+
package com.rhomobile.rhoconnect;
|
|
214
|
+
|
|
215
|
+
public class RhoconnectClient {
|
|
216
|
+
// ...
|
|
217
|
+
public boolean notifyOnCreate(String sourceName, String partition, Object objId, Object object);
|
|
218
|
+
public boolean notifyOnUpdate(String sourceName, String partition, Object objId, Object object);
|
|
219
|
+
public boolean notifyOnDelete(String sourceName, String partition, Object objId);
|
|
220
|
+
// ...
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
For example, `RhoconnectJavaSample` application uses the following implementation:
|
|
224
|
+
|
|
225
|
+
:::java
|
|
226
|
+
package com.rhomobile.contact.service;
|
|
227
|
+
import java.util.List;
|
|
228
|
+
|
|
229
|
+
import org.springframework.beans.factory.annotation.Autowired;
|
|
230
|
+
import org.springframework.stereotype.Service;
|
|
231
|
+
import org.springframework.transaction.annotation.Transactional;
|
|
232
|
+
|
|
233
|
+
import com.rhomobile.contact.dao.ContactDAO;
|
|
234
|
+
import com.rhomobile.contact.form.Contact;
|
|
235
|
+
|
|
236
|
+
import com.rhomobile.rhoconnect.RhoconnectClient;
|
|
237
|
+
//import org.apache.log4j.Logger;
|
|
238
|
+
|
|
239
|
+
@Service
|
|
240
|
+
public class ContactServiceImpl implements ContactService {
|
|
241
|
+
|
|
242
|
+
@Autowired
|
|
243
|
+
private ContactDAO contactDAO;
|
|
244
|
+
|
|
245
|
+
@Autowired
|
|
246
|
+
private RhoconnectClient client;
|
|
247
|
+
|
|
248
|
+
//private static final Logger logger = Logger.getLogger(ContactServiceImpl.class);
|
|
249
|
+
|
|
250
|
+
private static final String sourceName = "Contact"; // name of DAO model
|
|
251
|
+
|
|
252
|
+
// Data partitioning: i.e. your user name for filtering data on per user basis
|
|
253
|
+
private static final String partition = "your_partition";
|
|
254
|
+
|
|
255
|
+
@Transactional
|
|
256
|
+
public int addContact(Contact contact) {
|
|
257
|
+
int id = contactDAO.addContact(contact);
|
|
258
|
+
client.notifyOnCreate(sourceName, partition, Integer.toString(id), contact);
|
|
259
|
+
return id;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
@Transactional
|
|
263
|
+
public void updateContact(Contact contact) {
|
|
264
|
+
contactDAO.updateContact(contact);
|
|
265
|
+
client.notifyOnUpdate(sourceName, partition, Integer.toString(contact.getId()), contact);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
@Transactional
|
|
269
|
+
public void removeContact(Integer id) {
|
|
270
|
+
contactDAO.removeContact(id);
|
|
271
|
+
client.notifyOnDelete(sourceName, partition, Integer.toString(id));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
@Transactional
|
|
275
|
+
public List<Contact> listContact() {
|
|
276
|
+
return contactDAO.listContact();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
@Transactional
|
|
280
|
+
public Contact getContact(Integer id) {
|
|
281
|
+
return contactDAO.getContact(id);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
For more information about RhoConnect partitions, please refer to the [RhoConnect docs](http://docs.rhomobile.com/rhosync/source-adapters#data-partitioning).
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
## Meta
|
|
289
|
+
Created and maintained by Alexander Babichev.
|
|
290
|
+
|
|
291
|
+
Released under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
|
data/doc/rest-api.txt
CHANGED
|
@@ -337,6 +337,7 @@ Return content of a given document (client or source).
|
|
|
337
337
|
|
|
338
338
|
### `set_db_doc`
|
|
339
339
|
Sets the content of the specified server document. Data should be either a string or hash of hashes. Data type should be set accordingly.
|
|
340
|
+
If `append` flag is set to `true` , the data is appended to the current doc (if it exists) instead of replacing it.
|
|
340
341
|
|
|
341
342
|
:::ruby
|
|
342
343
|
RestClient.post(
|
|
@@ -345,7 +346,8 @@ Sets the content of the specified server document. Data should be either a strin
|
|
|
345
346
|
:api_token => token,
|
|
346
347
|
:doc => doc,
|
|
347
348
|
:data => data,
|
|
348
|
-
:data_type => data_type
|
|
349
|
+
:data_type => data_type,
|
|
350
|
+
:append => false
|
|
349
351
|
}.to_json,
|
|
350
352
|
:content_type => :json
|
|
351
353
|
)
|