rhoconnect-client 5.5.0

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.
Files changed (270) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +9 -0
  3. data/CREDITS +0 -0
  4. data/LICENSE +9 -0
  5. data/README.md +47 -0
  6. data/ext/rhoconnect-client/RhoConnectClient.rb +190 -0
  7. data/ext/rhoconnect-client/ext/RhoConnectClient.xml +726 -0
  8. data/ext/rhoconnect-client/ext/build +26 -0
  9. data/ext/rhoconnect-client/ext/build.bat +30 -0
  10. data/ext/rhoconnect-client/ext/platform/android/ext_java.files +1 -0
  11. data/ext/rhoconnect-client/ext/platform/android/ext_native.files +14 -0
  12. data/ext/rhoconnect-client/ext/platform/android/src/com/rhoconnectclient/RhoconnectClient.java +1 -0
  13. data/ext/rhoconnect-client/ext/platform/iphone/.gitignore +1 -0
  14. data/ext/rhoconnect-client/ext/platform/iphone/Rakefile +74 -0
  15. data/ext/rhoconnect-client/ext/platform/iphone/RhoconnectClient.xcodeproj/project.pbxproj +390 -0
  16. data/ext/rhoconnect-client/ext/platform/iphone/RhoconnectClient_Prefix.pch +7 -0
  17. data/ext/rhoconnect-client/ext/platform/iphone/impl/readme.txt +7 -0
  18. data/ext/rhoconnect-client/ext/platform/qt/Rakefile +35 -0
  19. data/ext/rhoconnect-client/ext/platform/qt/rhoconnect-client.pro +88 -0
  20. data/ext/rhoconnect-client/ext/platform/wm/Rhoconnect-client.sln +36 -0
  21. data/ext/rhoconnect-client/ext/platform/wm/Rhoconnect-client.vcproj +774 -0
  22. data/ext/rhoconnect-client/ext/platform/wm/Rhoconnect-client.vsprops +15 -0
  23. data/ext/rhoconnect-client/ext/platform/wm/src/rhoconnectclient_wm.cpp +40 -0
  24. data/ext/rhoconnect-client/ext/platform/wm/src/rhoconnectclient_wm.h +2 -0
  25. data/ext/rhoconnect-client/ext/platform/wp8/Rhoconnect-client.props +22 -0
  26. data/ext/rhoconnect-client/ext/platform/wp8/Rhoconnect-client.sln +32 -0
  27. data/ext/rhoconnect-client/ext/platform/wp8/Rhoconnect-client.vcxproj +220 -0
  28. data/ext/rhoconnect-client/ext/platform/wp8/Rhoconnect-client.vcxproj.filters +103 -0
  29. data/ext/rhoconnect-client/ext/shared/RhoConnectClientImpl.cpp +273 -0
  30. data/ext/rhoconnect-client/ext/shared/RhoConnectClientImpl.h +60 -0
  31. data/ext/rhoconnect-client/ext/shared/RhoConnectClientSingletonImpl.h +53 -0
  32. data/ext/rhoconnect-client/ext/shared/initRhoconnectClient.cpp +207 -0
  33. data/ext/rhoconnect-client/ext/shared/rhoconnectclient.c +18 -0
  34. data/ext/rhoconnect-client/ext/shared/sync/ClientRegister.cpp +398 -0
  35. data/ext/rhoconnect-client/ext/shared/sync/ClientRegister.h +147 -0
  36. data/ext/rhoconnect-client/ext/shared/sync/ISyncProtocol.h +91 -0
  37. data/ext/rhoconnect-client/ext/shared/sync/SyncEngine.cpp +1245 -0
  38. data/ext/rhoconnect-client/ext/shared/sync/SyncEngine.h +213 -0
  39. data/ext/rhoconnect-client/ext/shared/sync/SyncNotify.cpp +737 -0
  40. data/ext/rhoconnect-client/ext/shared/sync/SyncNotify.h +209 -0
  41. data/ext/rhoconnect-client/ext/shared/sync/SyncProtocol_3.h +220 -0
  42. data/ext/rhoconnect-client/ext/shared/sync/SyncProtocol_4.h +259 -0
  43. data/ext/rhoconnect-client/ext/shared/sync/SyncSource.cpp +1694 -0
  44. data/ext/rhoconnect-client/ext/shared/sync/SyncSource.h +212 -0
  45. data/ext/rhoconnect-client/ext/shared/sync/SyncThread.cpp +583 -0
  46. data/ext/rhoconnect-client/ext/shared/sync/SyncThread.h +250 -0
  47. data/ext/rhoconnect-client/ext.yml +12 -0
  48. data/lib/build/run_rhoconnect_spec.rb +135 -0
  49. data/lib/rhoconnect-client.rb +3 -0
  50. data/platform/shared/RhoConnectClient/RhoConnectClient.cpp +1673 -0
  51. data/platform/shared/RhoConnectClient/RhoConnectClient.h +181 -0
  52. data/platform/shared/RhoConnectClient/RhoError.h +77 -0
  53. data/rhoconnect-client/C++/Tests/RhoConnectClientTest.cpp +830 -0
  54. data/rhoconnect-client/C++/Tests/win32/.gitignore +3 -0
  55. data/rhoconnect-client/C++/Tests/win32/RhoConnectClient.sln +65 -0
  56. data/rhoconnect-client/C++/Tests/win32/RhoConnectClient.vcproj +634 -0
  57. data/rhoconnect-client/C++/Tests/win32/RhoConnectClientTest/RhoConnectClientTest.vcproj +222 -0
  58. data/rhoconnect-client/C++/Tests/win32/RhoConnectClientTest/stdafx.h +65 -0
  59. data/rhoconnect-client/C++/Tests/win32/stdafx.h +65 -0
  60. data/rhoconnect-client/CHANGELOG +18 -0
  61. data/rhoconnect-client/Java/Android/build/android.rake +387 -0
  62. data/rhoconnect-client/Java/Android/build/android_sdk.rb +582 -0
  63. data/rhoconnect-client/Java/Android/build/libcurl_build.files +73 -0
  64. data/rhoconnect-client/Java/Android/build/libjson_build.files +9 -0
  65. data/rhoconnect-client/Java/Android/build/librhocommon_build.files +14 -0
  66. data/rhoconnect-client/Java/Android/build/librhodb_build.files +5 -0
  67. data/rhoconnect-client/Java/Android/build/librhoimpl_build.files +13 -0
  68. data/rhoconnect-client/Java/Android/build/librholog_build.files +4 -0
  69. data/rhoconnect-client/Java/Android/build/libsqlite_build.files +1 -0
  70. data/rhoconnect-client/Java/Android/build/libsync_build.files +7 -0
  71. data/rhoconnect-client/Java/Android/build/libunzip_build.files +1 -0
  72. data/rhoconnect-client/Java/Android/build/rhoconnectclient_build.files +3 -0
  73. data/rhoconnect-client/Java/Android/build/rhoimpljava_build.files +21 -0
  74. data/rhoconnect-client/Java/Android/src/com/rhomobile/rhodes/Capabilities.java +63 -0
  75. data/rhoconnect-client/Java/Android/src/com/rhomobile/rhodes/MemoryInfoCollector.java +79 -0
  76. data/rhoconnect-client/Java/Android/src/com/rhomobile/rhodes/util/ContextFactory.java +63 -0
  77. data/rhoconnect-client/Java/Android/test/.classpath +9 -0
  78. data/rhoconnect-client/Java/Android/test/.project +33 -0
  79. data/rhoconnect-client/Java/Android/test/AndroidManifest.xml +14 -0
  80. data/rhoconnect-client/Java/Android/test/assets/apps/androidtest.png +0 -0
  81. data/rhoconnect-client/Java/Android/test/assets/apps/rhoconfig.txt +19 -0
  82. data/rhoconnect-client/Java/Android/test/assets/apps/rhoconfig.txt.timestamp +1 -0
  83. data/rhoconnect-client/Java/Android/test/assets/db/syncdb.schema +44 -0
  84. data/rhoconnect-client/Java/Android/test/assets/db/syncdb.triggers +10 -0
  85. data/rhoconnect-client/Java/Android/test/assets/db/syncdb_java.triggers +21 -0
  86. data/rhoconnect-client/Java/Android/test/assets/rho.dat +9 -0
  87. data/rhoconnect-client/Java/Android/test/proguard.cfg +36 -0
  88. data/rhoconnect-client/Java/Android/test/project.properties +11 -0
  89. data/rhoconnect-client/Java/Android/test/res/drawable-hdpi/icon.png +0 -0
  90. data/rhoconnect-client/Java/Android/test/res/drawable-ldpi/icon.png +0 -0
  91. data/rhoconnect-client/Java/Android/test/res/drawable-mdpi/icon.png +0 -0
  92. data/rhoconnect-client/Java/Android/test/res/layout/main.xml +12 -0
  93. data/rhoconnect-client/Java/Android/test/res/values/strings.xml +5 -0
  94. data/rhoconnect-client/Java/Android/test/rhoimpl.jar +0 -0
  95. data/rhoconnect-client/Java/Android/test/src/com/rhomobile/rhoconnect_client_test/TestRhoConnectClient.java +343 -0
  96. data/rhoconnect-client/Java/Android/test/src/com/rhomobile/rhoconnect_client_test/TestRhoConnectClientBlobs.java +219 -0
  97. data/rhoconnect-client/Java/RhoConnect/.classpath +6 -0
  98. data/rhoconnect-client/Java/RhoConnect/.project +93 -0
  99. data/rhoconnect-client/Java/RhoConnect/assets/apps/rhoconfig.txt +19 -0
  100. data/rhoconnect-client/Java/RhoConnect/assets/apps/rhoconfig.txt.timestamp +1 -0
  101. data/rhoconnect-client/Java/RhoConnect/assets/db/syncdb.schema +44 -0
  102. data/rhoconnect-client/Java/RhoConnect/assets/db/syncdb.triggers +10 -0
  103. data/rhoconnect-client/Java/RhoConnect/assets/db/syncdb_java.triggers +21 -0
  104. data/rhoconnect-client/Java/RhoConnect/assets/rho.dat +8 -0
  105. data/rhoconnect-client/Java/RhoConnect/jni/include/RhoConnectJniNotify.h +61 -0
  106. data/rhoconnect-client/Java/RhoConnect/jni/include/com_rhomobile_rhoconnect_RhoConnectClient.h +181 -0
  107. data/rhoconnect-client/Java/RhoConnect/jni/include/com_rhomobile_rhoconnect_RhoConnectNotify.h +13 -0
  108. data/rhoconnect-client/Java/RhoConnect/jni/include/com_rhomobile_rhoconnect_RhoConnectNotify_IDelegate.h +13 -0
  109. data/rhoconnect-client/Java/RhoConnect/jni/include/com_rhomobile_rhoconnect_RhoConnectObjectNotify.h +13 -0
  110. data/rhoconnect-client/Java/RhoConnect/jni/include/com_rhomobile_rhoconnect_RhoConnectObjectNotify_IDelegate.h +13 -0
  111. data/rhoconnect-client/Java/RhoConnect/jni/include/com_rhomobile_rhoconnect_RhomModel.h +103 -0
  112. data/rhoconnect-client/Java/RhoConnect/jni/include/rhojava.inc +76 -0
  113. data/rhoconnect-client/Java/RhoConnect/jni/src/RhoConnectJniClient.cpp +401 -0
  114. data/rhoconnect-client/Java/RhoConnect/jni/src/RhoConnectJniModel.cpp +332 -0
  115. data/rhoconnect-client/Java/RhoConnect/jni/src/RhoConnectJniNotify.cpp +223 -0
  116. data/rhoconnect-client/Java/RhoConnect/jni/src/RhoConnectUtil.cpp +82 -0
  117. data/rhoconnect-client/Java/RhoConnect/jni/src/RhodesApp.cpp +114 -0
  118. data/rhoconnect-client/Java/RhoConnect/src/com/rhomobile/rhoconnect/RhoConnectClient.java +108 -0
  119. data/rhoconnect-client/Java/RhoConnect/src/com/rhomobile/rhoconnect/RhoConnectNotify.java +78 -0
  120. data/rhoconnect-client/Java/RhoConnect/src/com/rhomobile/rhoconnect/RhoConnectObjectNotify.java +71 -0
  121. data/rhoconnect-client/Java/RhoConnect/src/com/rhomobile/rhoconnect/RhomModel.java +195 -0
  122. data/rhoconnect-client/JavaScript/.classpath +10 -0
  123. data/rhoconnect-client/JavaScript/.gitignore +4 -0
  124. data/rhoconnect-client/JavaScript/.project +17 -0
  125. data/rhoconnect-client/JavaScript/README.textile +1 -0
  126. data/rhoconnect-client/JavaScript/build.xml +185 -0
  127. data/rhoconnect-client/JavaScript/doc/fsm-sample.js +44 -0
  128. data/rhoconnect-client/JavaScript/doc/fsm-sample.png +0 -0
  129. data/rhoconnect-client/JavaScript/src/RhoSyncJS.gwt.xml +21 -0
  130. data/rhoconnect-client/JavaScript/stubs/RhoSyncStubsJS.gwt.xml +21 -0
  131. data/rhoconnect-client/JavaScript/stubs/com/rho/Capabilities.java +7 -0
  132. data/rhoconnect-client/JavaScript/stubs/com/rho/IRhoRubyHelper.java +7 -0
  133. data/rhoconnect-client/JavaScript/stubs/com/rho/Mutex.java +5 -0
  134. data/rhoconnect-client/JavaScript/stubs/com/rho/RhoAppAdapter.java +39 -0
  135. data/rhoconnect-client/JavaScript/stubs/com/rho/RhoClassFactory.java +29 -0
  136. data/rhoconnect-client/JavaScript/stubs/com/rho/RhoConf.java +100 -0
  137. data/rhoconnect-client/JavaScript/stubs/com/rho/RhoEmptyLogger.java +7 -0
  138. data/rhoconnect-client/JavaScript/stubs/com/rho/RhoEmptyProfiler.java +5 -0
  139. data/rhoconnect-client/JavaScript/stubs/com/rho/RhoLogger.java +32 -0
  140. data/rhoconnect-client/JavaScript/stubs/com/rho/RhoProfiler.java +27 -0
  141. data/rhoconnect-client/JavaScript/stubs/com/rho/RhodesApp.java +25 -0
  142. data/rhoconnect-client/JavaScript/stubs/com/rho/TimeInterval.java +22 -0
  143. data/rhoconnect-client/JavaScript/stubs/com/rho/Tokenizer.java +23 -0
  144. data/rhoconnect-client/JavaScript/stubs/com/rho/db/DBAdapter.java +174 -0
  145. data/rhoconnect-client/JavaScript/stubs/com/rho/db/DBAttrManager.java +15 -0
  146. data/rhoconnect-client/JavaScript/stubs/com/rho/db/DBException.java +5 -0
  147. data/rhoconnect-client/JavaScript/stubs/com/rho/db/IDBResult.java +27 -0
  148. data/rhoconnect-client/JavaScript/stubs/com/rho/file/IFileAccess.java +7 -0
  149. data/rhoconnect-client/JavaScript/stubs/com/rho/file/SimpleFile.java +15 -0
  150. data/rhoconnect-client/JavaScript/stubs/com/rho/net/IHttpConnection.java +22 -0
  151. data/rhoconnect-client/JavaScript/stubs/com/rho/net/NetRequest.java +324 -0
  152. data/rhoconnect-client/JavaScript/stubs/com/rho/net/NetResponse.java +51 -0
  153. data/rhoconnect-client/JavaScript/stubs/com/rho/net/URI.java +64 -0
  154. data/rhoconnect-client/JavaScript/stubs/com/rho/sync/ClientRegister.java +15 -0
  155. data/rhoconnect-client/JavaScript/stubs/com/rho/sync/JSONArrayIterator.java +37 -0
  156. data/rhoconnect-client/JavaScript/stubs/com/rho/sync/JSONEntry.java +48 -0
  157. data/rhoconnect-client/JavaScript/stubs/com/rho/sync/JSONStructIterator.java +41 -0
  158. data/rhoconnect-client/JavaScript/stubs/com/rho/sync/SyncNotify.java +98 -0
  159. data/rhoconnect-client/JavaScript/stubs/com/rho/sync/SyncThread.java +92 -0
  160. data/rhoconnect-client/JavaScript/war/WEB-INF/lib/gwt-servlet-deps.jar +0 -0
  161. data/rhoconnect-client/JavaScript/war/WEB-INF/lib/gwt-servlet.jar +0 -0
  162. data/rhoconnect-client/JavaScript/war/js/fsm-sample.js +54 -0
  163. data/rhoconnect-client/JavaScript/war/js/rhosync-api.js +237 -0
  164. data/rhoconnect-client/JavaScript/war/js/rhosync-fsm.js +307 -0
  165. data/rhoconnect-client/JavaScript/war/rhosyncjs/4C71D69C9BBC9E6F05C6BA49B01BCBC1.cache.html +3122 -0
  166. data/rhoconnect-client/JavaScript/war/rhosyncjs/5146F4FFF34511C8BB2661E920B49E3A.cache.html +3254 -0
  167. data/rhoconnect-client/JavaScript/war/rhosyncjs/5248C67481D9D27AD0703D15CDBD2A1C.cache.html +3147 -0
  168. data/rhoconnect-client/JavaScript/war/rhosyncjs/EE1DC2692C9C32367B53A39E2358AF23.cache.html +3195 -0
  169. data/rhoconnect-client/JavaScript/war/rhosyncjs/clear.cache.gif +0 -0
  170. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/corner.png +0 -0
  171. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/corner_ie6.png +0 -0
  172. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/hborder.png +0 -0
  173. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/hborder_ie6.png +0 -0
  174. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/ie6/corner_dialog_topleft.png +0 -0
  175. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/ie6/corner_dialog_topright.png +0 -0
  176. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/ie6/hborder_blue_shadow.png +0 -0
  177. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/ie6/hborder_gray_shadow.png +0 -0
  178. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/ie6/vborder_blue_shadow.png +0 -0
  179. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/ie6/vborder_gray_shadow.png +0 -0
  180. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/splitPanelThumb.png +0 -0
  181. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/vborder.png +0 -0
  182. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/images/vborder_ie6.png +0 -0
  183. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/standard.css +1144 -0
  184. data/rhoconnect-client/JavaScript/war/rhosyncjs/gwt/standard/standard_rtl.css +1145 -0
  185. data/rhoconnect-client/JavaScript/war/rhosyncjs/hosted.html +350 -0
  186. data/rhoconnect-client/JavaScript/war/rhosyncjs/rhosyncjs.nocache.js +314 -0
  187. data/rhoconnect-client/JavaScript/war/test/SpecRunner.html +35 -0
  188. data/rhoconnect-client/JavaScript/war/test/dbtest.html +38 -0
  189. data/rhoconnect-client/JavaScript/war/test/lib/jasmine-1.0.1/MIT.LICENSE +20 -0
  190. data/rhoconnect-client/JavaScript/war/test/lib/jasmine-1.0.1/jasmine-html.js +188 -0
  191. data/rhoconnect-client/JavaScript/war/test/lib/jasmine-1.0.1/jasmine.css +166 -0
  192. data/rhoconnect-client/JavaScript/war/test/lib/jasmine-1.0.1/jasmine.js +2421 -0
  193. data/rhoconnect-client/JavaScript/war/test/spec/SpecHelper.js +7 -0
  194. data/rhoconnect-client/JavaScript/war/test/spec/SyncApiSpec.js +573 -0
  195. data/rhoconnect-client/JavaScript/war/test/spec/samples/PlayerSpec.js +58 -0
  196. data/rhoconnect-client/JavaScript/war/test/worker-test.js +17 -0
  197. data/rhoconnect-client/LICENSE +41 -0
  198. data/rhoconnect-client/ObjectiveC/RhoConnectClient.h +118 -0
  199. data/rhoconnect-client/ObjectiveC/RhoConnectClient.m +641 -0
  200. data/rhoconnect-client/ObjectiveC/RhoConnectClient.xcodeproj/project.pbxproj +1434 -0
  201. data/rhoconnect-client/ObjectiveC/RhoConnectNotify.h +83 -0
  202. data/rhoconnect-client/ObjectiveC/RhoConnectNotify.m +181 -0
  203. data/rhoconnect-client/ObjectiveC/RhoConnectObjectNotify.h +65 -0
  204. data/rhoconnect-client/ObjectiveC/RhoConnectObjectNotify.m +73 -0
  205. data/rhoconnect-client/ObjectiveC/RhomModel.h +101 -0
  206. data/rhoconnect-client/ObjectiveC/RhomModel.m +320 -0
  207. data/rhoconnect-client/ObjectiveC/Tests/RhoConnectClientTest/MainWindow.xib +198 -0
  208. data/rhoconnect-client/ObjectiveC/Tests/RhoConnectClientTest/RhoConnectClientTest-Info.plist +30 -0
  209. data/rhoconnect-client/ObjectiveC/Tests/RhoConnectClientTest/RhoConnectClientTest.xcodeproj/project.pbxproj +373 -0
  210. data/rhoconnect-client/ObjectiveC/Tests/RhoConnectClientTest/RhoConnectClientTestAppDelegate.h +58 -0
  211. data/rhoconnect-client/ObjectiveC/Tests/RhoConnectClientTest/RhoConnectClientTestAppDelegate.m +84 -0
  212. data/rhoconnect-client/ObjectiveC/Tests/RhoConnectClientTest/RhoConnectClientTest_Prefix.pch +8 -0
  213. data/rhoconnect-client/ObjectiveC/Tests/RhoConnectClientTest/invalid_import_db.zip +0 -0
  214. data/rhoconnect-client/ObjectiveC/Tests/RhoConnectClientTest/main.m +1096 -0
  215. data/rhoconnect-client/ObjectiveC/Tests/RhoConnectClientTest/test.png +0 -0
  216. data/rhoconnect-client/ObjectiveC/Tests/RhoConnectClientTest/test2.png +0 -0
  217. data/rhoconnect-client/ObjectiveC/Tests/RhoConnectClientTest/valid_import_db.zip +0 -0
  218. data/rhoconnect-client/ObjectiveC/Tests/ptests/Classes/ptestsAppDelegate.h +62 -0
  219. data/rhoconnect-client/ObjectiveC/Tests/ptests/Classes/ptestsAppDelegate.m +35 -0
  220. data/rhoconnect-client/ObjectiveC/Tests/ptests/Classes/ptestsViewController.h +78 -0
  221. data/rhoconnect-client/ObjectiveC/Tests/ptests/Classes/ptestsViewController.m +549 -0
  222. data/rhoconnect-client/ObjectiveC/Tests/ptests/MainWindow.xib +227 -0
  223. data/rhoconnect-client/ObjectiveC/Tests/ptests/main.m +17 -0
  224. data/rhoconnect-client/ObjectiveC/Tests/ptests/ptests-Info.plist +30 -0
  225. data/rhoconnect-client/ObjectiveC/Tests/ptests/ptests.xcodeproj/project.pbxproj +363 -0
  226. data/rhoconnect-client/ObjectiveC/Tests/ptests/ptestsViewController.xib +641 -0
  227. data/rhoconnect-client/ObjectiveC/Tests/ptests/ptests_Prefix.pch +8 -0
  228. data/rhoconnect-client/README.textile +23 -0
  229. data/rhoconnect-client/Rakefile +20 -0
  230. data/rhoconnect-client/Samples/Java/android_store/.classpath +8 -0
  231. data/rhoconnect-client/Samples/Java/android_store/.project +33 -0
  232. data/rhoconnect-client/Samples/Java/android_store/AndroidManifest.xml +24 -0
  233. data/rhoconnect-client/Samples/Java/android_store/assets/apps/rhoconfig.txt +19 -0
  234. data/rhoconnect-client/Samples/Java/android_store/assets/apps/rhoconfig.txt.timestamp +1 -0
  235. data/rhoconnect-client/Samples/Java/android_store/assets/db/syncdb.schema +44 -0
  236. data/rhoconnect-client/Samples/Java/android_store/assets/db/syncdb.triggers +10 -0
  237. data/rhoconnect-client/Samples/Java/android_store/assets/db/syncdb_java.triggers +21 -0
  238. data/rhoconnect-client/Samples/Java/android_store/assets/rho.dat +8 -0
  239. data/rhoconnect-client/Samples/Java/android_store/default.properties +11 -0
  240. data/rhoconnect-client/Samples/Java/android_store/project.properties +14 -0
  241. data/rhoconnect-client/Samples/Java/android_store/res/drawable-hdpi/icon.png +0 -0
  242. data/rhoconnect-client/Samples/Java/android_store/res/drawable-ldpi/icon.png +0 -0
  243. data/rhoconnect-client/Samples/Java/android_store/res/drawable-mdpi/icon.png +0 -0
  244. data/rhoconnect-client/Samples/Java/android_store/res/layout/main.xml +12 -0
  245. data/rhoconnect-client/Samples/Java/android_store/res/values/strings.xml +5 -0
  246. data/rhoconnect-client/Samples/Java/android_store/rhoimpl.jar +0 -0
  247. data/rhoconnect-client/Samples/Java/android_store/src/com/rhomobile/android_store/StoreActivity.java +68 -0
  248. data/rhoconnect-client/Samples/Java/android_store/src/com/rhomobile/android_store/StoreApplication.java +15 -0
  249. data/rhoconnect-client/Samples/ObjectiveC/store/Classes/LoginViewController.h +70 -0
  250. data/rhoconnect-client/Samples/ObjectiveC/store/Classes/LoginViewController.m +94 -0
  251. data/rhoconnect-client/Samples/ObjectiveC/store/Classes/RhoConnectEngine.h +82 -0
  252. data/rhoconnect-client/Samples/ObjectiveC/store/Classes/RhoConnectEngine.m +119 -0
  253. data/rhoconnect-client/Samples/ObjectiveC/store/Classes/RootViewController.h +63 -0
  254. data/rhoconnect-client/Samples/ObjectiveC/store/Classes/RootViewController.m +314 -0
  255. data/rhoconnect-client/Samples/ObjectiveC/store/Classes/WaitLoginController.h +65 -0
  256. data/rhoconnect-client/Samples/ObjectiveC/store/Classes/WaitLoginController.m +110 -0
  257. data/rhoconnect-client/Samples/ObjectiveC/store/Classes/storeAppDelegate.h +61 -0
  258. data/rhoconnect-client/Samples/ObjectiveC/store/Classes/storeAppDelegate.m +171 -0
  259. data/rhoconnect-client/Samples/ObjectiveC/store/LoginViewController.xib +779 -0
  260. data/rhoconnect-client/Samples/ObjectiveC/store/MainWindow.xib +580 -0
  261. data/rhoconnect-client/Samples/ObjectiveC/store/RootViewController.xib +384 -0
  262. data/rhoconnect-client/Samples/ObjectiveC/store/WaitLoginController.xib +557 -0
  263. data/rhoconnect-client/Samples/ObjectiveC/store/icon.png +0 -0
  264. data/rhoconnect-client/Samples/ObjectiveC/store/main.m +22 -0
  265. data/rhoconnect-client/Samples/ObjectiveC/store/store-Info.plist +30 -0
  266. data/rhoconnect-client/Samples/ObjectiveC/store/store.xcodeproj/project.pbxproj +367 -0
  267. data/rhoconnect-client/Samples/ObjectiveC/store/store_Prefix.pch +14 -0
  268. data/rhoconnect-client/build.yml +3 -0
  269. data/rhoconnect-client/version +1 -0
  270. metadata +314 -0
@@ -0,0 +1,1694 @@
1
+ /*------------------------------------------------------------------------
2
+ * (The MIT License)
3
+ *
4
+ * Copyright (c) 2008-2011 Rhomobile, Inc.
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ * THE SOFTWARE.
23
+ *
24
+ * http://rhomobile.com
25
+
26
+ * Copyright (c) 2011-2016 Symbol Technologies, Inc.
27
+ *
28
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
29
+ * of this software and associated documentation files (the "Software"), to deal
30
+ * in the Software without restriction, including without limitation the rights
31
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32
+ * copies of the Software, and to permit persons to whom the Software is
33
+ * furnished to do so, subject to the following conditions:
34
+ *
35
+ * The above copyright notice and this permission notice shall be included in
36
+ * all copies or substantial portions of the Software.
37
+ *
38
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44
+ * THE SOFTWARE.
45
+ *
46
+ * http://symbol.com
47
+ *------------------------------------------------------------------------*/
48
+
49
+ #include "SyncSource.h"
50
+ #include "SyncEngine.h"
51
+ #include "SyncThread.h"
52
+
53
+ #include "common/RhoTime.h"
54
+ #include "common/StringConverter.h"
55
+ #include "common/RhodesApp.h"
56
+ #include "common/Tokenizer.h"
57
+ #include "common/RhoFilePath.h"
58
+ #include "common/RhoFile.h"
59
+ #include "common/RhoAppAdapter.h"
60
+ #include "common/RhoConf.h"
61
+ #include "json/JSONIterator.h"
62
+ #include "statistic/RhoProfiler.h"
63
+ #include "net/URI.h"
64
+ #ifndef RHO_NO_RUBY
65
+ #include "ruby/ext/rho/rhoruby.h"
66
+ #endif //RHO_NO_RUBY
67
+
68
+
69
+ namespace rho {
70
+ namespace sync {
71
+ IMPLEMENT_LOGCLASS(CSyncSource,"Sync");
72
+
73
+ using namespace rho::net;
74
+ using namespace rho::db;
75
+ using namespace rho::common;
76
+ using namespace rho::json;
77
+ /*
78
+ CSyncSource::CSyncSource() : m_syncEngine( *new CSyncEngine(*new db::CDBAdapter()))
79
+ {
80
+ m_bTokenFromDB = true;
81
+
82
+ m_nCurPageCount = 0;
83
+ m_nInserted = 0;
84
+ m_nDeleted = 0;
85
+ m_nTotalCount = 0;
86
+
87
+ m_nErrCode = RhoAppAdapter.ERR_NONE;
88
+
89
+ m_bIsSearch = false;
90
+ }
91
+ */
92
+ CSyncSource::CSyncSource(CSyncEngine& syncEngine, db::CDBAdapter& db ) : m_syncEngine(syncEngine), m_dbAdapter(db)
93
+ {
94
+ m_bTokenFromDB = true;
95
+ m_nProgressStep = 0;
96
+ m_nCurPageCount = 0;
97
+ m_nInserted = 0;
98
+ m_nDeleted = 0;
99
+ m_nTotalCount = 0;
100
+ m_nRefreshTime = 0;
101
+
102
+ m_nErrCode = RhoAppAdapter.ERR_NONE;
103
+ m_bSchemaSource = db.isTableExist(m_strName);
104
+ }
105
+
106
+ CSyncSource::CSyncSource(int id, const String& strName, const String& strSyncType, db::CDBAdapter& db, CSyncEngine& syncEngine ) : m_syncEngine(syncEngine), m_dbAdapter(db)
107
+ {
108
+ m_nID = id;
109
+ m_strName = strName;
110
+ m_strSyncType = strSyncType;
111
+ m_nProgressStep = 0;
112
+
113
+ m_nCurPageCount = 0;
114
+ m_nInserted = 0;
115
+ m_nDeleted = 0;
116
+ m_nTotalCount = 0;
117
+ m_nRefreshTime = 0;
118
+
119
+ m_nErrCode = RhoAppAdapter.ERR_NONE;
120
+
121
+ IDBResult res = db.executeSQL("SELECT token,associations from sources WHERE source_id=?", m_nID);
122
+ if ( !res.isEnd() )
123
+ {
124
+ m_token = res.getUInt64ByIdx(0);
125
+ m_bTokenFromDB = true;
126
+ }else
127
+ {
128
+ m_token = 0;
129
+ m_bTokenFromDB = true;
130
+ }
131
+
132
+ m_bSchemaSource = db.isTableExist(m_strName);
133
+ parseAssociations(res.getStringByIdx(1));
134
+ }
135
+
136
+ void CSyncSource::parseAssociations(const String& strAssociations)
137
+ {
138
+ if (strAssociations.length() == 0 )
139
+ return;
140
+
141
+ CTokenizer oTokenizer( strAssociations, "," );
142
+
143
+ String strSrcName = "";
144
+ while (oTokenizer.hasMoreTokens())
145
+ {
146
+ String tok = oTokenizer.nextToken();
147
+ if (tok.length() == 0)
148
+ continue;
149
+
150
+ if ( strSrcName.length() > 0 )
151
+ {
152
+ m_arAssociations.addElement( CAssociation(strSrcName, tok) );
153
+ strSrcName = "";
154
+ }else
155
+ strSrcName = tok;
156
+ }
157
+ }
158
+
159
+ net::CNetRequestWrapper CSyncSource::getNet(){ return getSync().getNet(); }
160
+ CSyncNotify& CSyncSource::getNotify(){ return getSync().getNotify(); }
161
+ ISyncProtocol& CSyncSource::getProtocol(){ return getSync().getProtocol(); }
162
+
163
+ void CSyncSource::sync()
164
+ {
165
+ getNotify().reportSyncStatus(RhoAppAdapter.getMessageText("syncronizing") + getName() + "...", m_nErrCode, m_strError );
166
+
167
+ CTimeInterval startTime = CTimeInterval::getCurrentTime();
168
+ //m_bIsSearch = false;
169
+
170
+ // if ( isTokenFromDB() && getToken() > 1 )
171
+ // syncServerChanges(); //sync only server changes, which was paused before
172
+ // else
173
+ // {
174
+ if ( isEmptyToken() )
175
+ processToken(1);
176
+
177
+ syncClientChanges();
178
+ syncServerChanges();
179
+
180
+ /*
181
+ boolean bSyncedServer = syncClientChanges();
182
+ if ( !bSyncedServer )
183
+ syncServerChanges();
184
+ */
185
+ // }
186
+
187
+ CTimeInterval endTime = CTimeInterval::getCurrentTime();
188
+
189
+ int nSyncSucess = m_nErrCode == RhoAppAdapter.ERR_NONE ? 1 : 0;
190
+ if ( nSyncSucess > 0 )
191
+ getDB().executeSQL( "UPDATE sources set last_updated=?,last_inserted_size=?,last_deleted_size=?, \
192
+ last_sync_duration=?,last_sync_success=?, backend_refresh_time=? WHERE source_id=?",
193
+ CLocalTime().toULong(), getInsertedCount(), getDeletedCount(), (endTime-startTime).toULong(), nSyncSucess, m_nRefreshTime,
194
+ getID() );
195
+ else
196
+ getDB().executeSQL( "UPDATE sources set last_inserted_size=?,last_deleted_size=?, \
197
+ last_sync_duration=?,last_sync_success=?, backend_refresh_time=? WHERE source_id=?",
198
+ getInsertedCount(), getDeletedCount(), (endTime-startTime).toULong(), nSyncSucess, m_nRefreshTime,
199
+ getID() );
200
+
201
+ }
202
+
203
+ void CSyncSource::syncClientChanges()
204
+ {
205
+ PROF_START("Pull");
206
+
207
+ boolean bSyncClient = haveChangedValues();
208
+
209
+ if ( bSyncClient )
210
+ doSyncClientChanges();
211
+
212
+ PROF_STOP("Pull");
213
+ }
214
+
215
+ /*
216
+ boolean CSyncSource::syncClientChanges()
217
+ {
218
+ boolean bSyncedServer = false;
219
+ if ( isPendingClientChanges() )
220
+ {
221
+ LOG(INFO) + "Client has unconfirmed created items. Call server to update them.";
222
+ syncServerChanges();
223
+ bSyncedServer = true;
224
+ }
225
+
226
+ if ( bSyncedServer && isPendingClientChanges() )
227
+ {
228
+ LOG(INFO) + "Server does not sent created items. Stop sync.";
229
+ getSync().setState(CSyncEngine::esStop);
230
+ }
231
+ else
232
+ {
233
+ PROF_START("Pull");
234
+
235
+ boolean bSyncClient = false;
236
+ {
237
+ IDBResult res = getDB().executeSQL("SELECT object FROM changed_values WHERE source_id=? LIMIT 1 OFFSET 0", getID());
238
+ bSyncClient = !res.isEnd();
239
+ }
240
+ if ( bSyncClient )
241
+ {
242
+ doSyncClientChanges();
243
+ bSyncedServer = false;
244
+ }
245
+
246
+ PROF_STOP("Pull");
247
+ }
248
+
249
+ return bSyncedServer;
250
+ }
251
+
252
+ boolean CSyncSource::isPendingClientChanges()
253
+ {
254
+ IDBResult res = getDB().executeSQL("SELECT object FROM changed_values WHERE source_id=? and update_type='create' and sent>1 LIMIT 1 OFFSET 0", getID());
255
+ return !res.isEnd();
256
+ }*/
257
+
258
+ void CSyncSource::addBelongsTo(const String& strAttrib, int nSrcID)
259
+ {
260
+ m_hashBelongsTo.put(strAttrib, nSrcID);
261
+ }
262
+
263
+ int CSyncSource::getBelongsToSrcID(const String& strAttrib)
264
+ {
265
+ if ( m_hashBelongsTo.containsKey(strAttrib) )
266
+ return m_hashBelongsTo.get(strAttrib);
267
+
268
+ return -1;
269
+ }
270
+
271
+ void CSyncSource::checkIgnorePushObjects()
272
+ {
273
+ // ignore changes in pending creates
274
+ {
275
+ IDBResult res = getDB().executeSQL("SELECT distinct(object) FROM changed_values where source_id=? and sent>=2", getID() );
276
+ for( ; !res.isEnd(); res.next() )
277
+ {
278
+ String strObject = res.getStringByIdx(0);
279
+ m_hashIgnorePushObjects.put(strObject, 1);
280
+ }
281
+ }
282
+
283
+ //check for belongs_to
284
+ String strAttribQuests = "";
285
+ Vector<String> arValues;
286
+ arValues.addElement(convertToStringA(getID()));
287
+ for ( Hashtable<String,int>::iterator it = m_hashBelongsTo.begin(); it != m_hashBelongsTo.end(); ++it )
288
+ {
289
+ if ( strAttribQuests.length() > 0 )
290
+ strAttribQuests += ",";
291
+
292
+ strAttribQuests += "?";
293
+ arValues.addElement(it->first);
294
+ }
295
+
296
+ if ( strAttribQuests.length() > 0 )
297
+ {
298
+ IDBResult res = getDB().executeSQLEx( (String("SELECT object, attrib, value FROM changed_values where source_id=? and sent<=1 and attrib IN ( ") + strAttribQuests + " )").c_str(),
299
+ arValues );
300
+
301
+ for( ; !res.isEnd(); res.next() )
302
+ {
303
+ String strObject = res.getStringByIdx(0);
304
+ String strAttrib = res.getStringByIdx(1);
305
+ String strValue = res.getStringByIdx(2);
306
+
307
+ IDBResult res2 = getDB().executeSQL(
308
+ "SELECT object FROM changed_values where source_id=? and sent>=2 and object=? LIMIT 1 OFFSET 0",
309
+ getBelongsToSrcID(strAttrib), strValue );
310
+
311
+ if (!res2.isEnd())
312
+ m_hashIgnorePushObjects.put(strObject, 1);
313
+
314
+ }
315
+ }
316
+ }
317
+
318
+ void CSyncSource::doSyncClientChanges()
319
+ {
320
+ String arUpdateTypes[] = {"create", "update", "delete"};
321
+ boolean arUpdateSent[] = {false, false, false};
322
+
323
+ m_arMultipartItems.removeAllElements();
324
+ m_arBlobAttrs.removeAllElements();
325
+ String strBody = "{\"source_name\":" + CJSONEntry::quoteValue(getName()) + ",\"client_id\":" + CJSONEntry::quoteValue(getSync().getClientID());
326
+ boolean bSend = false;
327
+ int i = 0;
328
+
329
+ getDB().Lock();
330
+ getDB().updateAllAttribChanges();
331
+ checkIgnorePushObjects();
332
+ if ( getSync().getSourceOptions().getBoolProperty(getID(), "full_update") )
333
+ getDB().updateFullUpdateChanges( getID() );
334
+
335
+ for( i = 0; i < 3; i++ )
336
+ {
337
+ String strBody1;
338
+ makePushBody_Ver3(strBody1, arUpdateTypes[i], true);
339
+ if (strBody1.length() > 0)
340
+ {
341
+ strBody += "," + strBody1;
342
+
343
+ String strBlobAttrs = "";
344
+ for ( int j = 0; j < (int)m_arBlobAttrs.size(); j++)
345
+ {
346
+ if ( strBlobAttrs.length() > 0 )
347
+ strBlobAttrs += ",";
348
+
349
+ strBlobAttrs += CJSONEntry::quoteValue(m_arBlobAttrs.elementAt(j));
350
+ }
351
+
352
+ if ( strBlobAttrs.length() > 0 )
353
+ strBody += ",\"blob_fields\":[" + strBlobAttrs + "]";
354
+
355
+ arUpdateSent[i] = true;
356
+ bSend = true;
357
+ }
358
+ }
359
+
360
+ if (!bSend)
361
+ {
362
+ //check for push_changes
363
+ IDBResult res = getDB().executeSQL("SELECT attrib_type FROM changed_values where source_id=? and update_type =?", getID(), "push_changes" );
364
+ bSend = !res.isEnd();
365
+ }
366
+
367
+ strBody += "}";
368
+
369
+ getDB().Unlock();
370
+
371
+ if ( bSend && getSync().isContinueSync())
372
+ {
373
+ LOG(INFO) + "Push client changes to server. Source: " + getName() + "Size :" + strBody.length();
374
+ if ( !RHOCONF().getBool("log_skip_post") )
375
+ LOG(TRACE) + "Push body: " + strBody;
376
+
377
+ if ( getSync().getSourceOptions().getBoolProperty(getID(), "set_sync_push_body" ) )
378
+ getSync().getSourceOptions().setProperty(getID(), "sync_push_body", strBody.c_str() );
379
+
380
+ if ( getSync().getSourceOptions().getIntProperty(getID(), "sync_push_error" ) > 0 )
381
+ {
382
+ m_nErrCode = getSync().getSourceOptions().getIntProperty(getID(), "sync_push_error" );
383
+ m_strError = getSync().getSourceOptions().getProperty(getID(), "sync_push_error_text" );
384
+ }else
385
+ {
386
+ Hashtable<String, String> reqHeaders;
387
+ reqHeaders.put(getProtocol().getClientIDHeader(), getSync().getClientID());
388
+ if ( m_arMultipartItems.size() > 0 )
389
+ {
390
+ CMultipartItem* pItem = new CMultipartItem();
391
+ CMultipartItem& oItem = *pItem;
392
+ oItem.m_strBody = strBody;
393
+ //oItem.m_strContentType = getProtocol().getContentType();
394
+ oItem.m_strName = "cud";
395
+ m_arMultipartItems.addElement(pItem);
396
+
397
+ NetResponse resp = getNet().pushMultipartData( getProtocol().getClientChangesUrl(getName()), m_arMultipartItems, &getSync(), &reqHeaders);
398
+ if ( !resp.isOK() )
399
+ {
400
+ //getSync().stopSync();
401
+ m_nErrCode = RhoAppAdapter.getErrorFromResponse(resp);
402
+ m_strError = resp.getCharData();
403
+ }
404
+ }else
405
+ {
406
+ NetResponse resp = getNet().doRequest("POST", getProtocol().getClientChangesUrl(getName()), strBody, &getSync(), &reqHeaders);
407
+ if ( !resp.isOK() )
408
+ {
409
+ //getSync().stopSync();
410
+ m_nErrCode = RhoAppAdapter.getErrorFromResponse(resp);
411
+ m_strError = resp.getCharData();
412
+ }
413
+ }
414
+ }
415
+
416
+ #ifndef RHO_NO_RUBY
417
+ if ( getSync().isNoThreadedMode() && getSync().getSourceOptions().getProperty(getID(), "sync_push_callback" ).length() > 0 )
418
+ rho_ruby_callmethod( getSync().getSourceOptions().getProperty(getID(), "sync_push_callback" ).c_str() );
419
+ #endif //RHO_NO_RUBY
420
+
421
+ getDB().Lock();
422
+ for( i = 0; i < 3; i++ )
423
+ {
424
+ if ( arUpdateSent[i] )
425
+ {
426
+ if ( m_nErrCode == RhoAppAdapter.ERR_NONE )
427
+ {
428
+ //oo conflicts
429
+ if ( i < 1 && !getSync().getSourceOptions().getBoolProperty(getID(), "pass_through") ) //create
430
+ getDB().executeSQL("UPDATE changed_values SET sent=2 WHERE source_id=? and update_type=? and sent=1", getID(), arUpdateTypes[i] );
431
+ else
432
+ //
433
+ getDB().executeSQL("DELETE FROM changed_values WHERE source_id=? and update_type=? and sent=1", getID(), arUpdateTypes[i] );
434
+ }else
435
+ {
436
+ if ( i == 0 ) //create
437
+ {
438
+ //remove deleted while sync objects
439
+ Hashtable<String,int> hashDeletes;
440
+ {
441
+ IDBResult res = getDB().executeSQL("SELECT distinct(object) FROM changed_values where source_id=? and update_type=? and sent=0", getID(), "delete" );
442
+ for( ; !res.isEnd(); res.next() )
443
+ hashDeletes.put( res.getStringByIdx(0), 1 );
444
+ }
445
+
446
+ Vector<String> arObjs;
447
+ IDBResult res = getDB().executeSQL("SELECT distinct(object) FROM changed_values where source_id=? and update_type=? and sent=1", getID(), arUpdateTypes[i] );
448
+ for( ; !res.isEnd(); res.next() )
449
+ arObjs.addElement( res.getStringByIdx(0) );
450
+
451
+ for ( int j = 0; j < (int)arObjs.size(); j++ )
452
+ {
453
+ if ( !hashDeletes.containsKey(arObjs[j]) )
454
+ getDB().executeSQL("INSERT INTO changed_values(update_type, attrib, source_id, object) VALUES(?,?,?,?)", arUpdateTypes[i], "object", getID(), arObjs[j] );
455
+ }
456
+
457
+ for ( int j = 0; j < (int)arObjs.size(); j++ )
458
+ getDB().executeSQL("DELETE FROM changed_values WHERE source_id=? and object=? and attrib<>?", getID(), arObjs[j], "object" );
459
+
460
+ }
461
+ else if ( i == 1 )//update
462
+ {
463
+ //remove updates with sent=1 if sent=0 exists
464
+ Vector<String> arObjs, arAttribs;
465
+ IDBResult res = getDB().executeSQL("SELECT object, attrib FROM changed_values where source_id=? and update_type=? and sent=0", getID(), arUpdateTypes[i] );
466
+ for( ; !res.isEnd(); res.next() )
467
+ {
468
+ arObjs.addElement( res.getStringByIdx(0) );
469
+ arAttribs.addElement( res.getStringByIdx(1) );
470
+ }
471
+ for ( int j = 0; j < (int)arObjs.size(); j++ )
472
+ {
473
+ getDB().executeSQL("DELETE FROM changed_values WHERE source_id=? and object=? and attrib=? and update_type = ? and sent=1", getID(), arObjs[j], arAttribs[j], arUpdateTypes[i] );
474
+ }
475
+
476
+ getDB().executeSQL("UPDATE changed_values SET sent=0 WHERE source_id=? and update_type=? and sent=1", getID(), arUpdateTypes[i] );
477
+ }
478
+ else
479
+ getDB().executeSQL("UPDATE changed_values SET sent=0 WHERE source_id=? and update_type=? and sent=1", getID(), arUpdateTypes[i] );
480
+ }
481
+ }
482
+ }
483
+
484
+ if (m_nErrCode == RhoAppAdapter.ERR_NONE)
485
+ getDB().executeSQL("DELETE FROM changed_values WHERE source_id=? and update_type=?", getID(), "push_changes" );
486
+
487
+ getDB().Unlock();
488
+ }
489
+
490
+ m_arMultipartItems.removeAllElements();
491
+ m_arBlobAttrs.removeAllElements();
492
+ }
493
+ /*
494
+ static void escapeDoubleQuotes(String& str)
495
+ {
496
+ const char* szQuote = strchr(str.c_str(), '\"');
497
+ while(szQuote)
498
+ {
499
+ int nPos = szQuote - str.c_str();
500
+ str.insert(nPos, 1, '\\');
501
+ if ( nPos+2 < str.length() )
502
+ szQuote = strchr(str.c_str()+nPos+2, '\"');
503
+ else
504
+ szQuote = 0;
505
+ }
506
+ }*/
507
+
508
+ //{"source_name":"SampleAdapter","client_id":1,"create":{"1":{"brand":"Apple","name":"iPhone","price":"199.99"}}}
509
+ //{"source_name":"SampleAdapter","client_id":1,"update":{"1":{"brand":"Apple","name":"iPhone","price":"199.99"}}}
510
+ //{"source_name":"SampleAdapter","client_id":1,"delete":{"1":{"brand":"Apple","name":"iPhone","price":"199.99"}}}
511
+ //{"source_name":"SampleAdapter","client_id":1,"delete":{"3":{"brand":"HTC","name":"Fuze","price":"299.99"}},"create":{"1":{"brand":"Apple","name":"iPhone","price":"199.99"}},"update":{"2":{"brand":"Android","name":"G2","price":"99.99"}}}
512
+ void CSyncSource::makePushBody_Ver3(String& strBody, const String& strUpdateType, boolean isSync)
513
+ {
514
+ getDB().Lock();
515
+
516
+ //if ( isSync )
517
+ // getDB().updateAllAttribChanges();
518
+
519
+ IDBResult res = getDB().executeSQL("SELECT attrib, object, value, attrib_type "
520
+ "FROM changed_values where source_id=? and update_type =? and sent<=1 ORDER BY object", getID(), strUpdateType.c_str() );
521
+
522
+ if ( res.isEnd() )
523
+ {
524
+ getDB().Unlock();
525
+ return;
526
+ }
527
+
528
+ String strCurObject = "";
529
+ boolean bFirst = true;
530
+ for( ; !res.isEnd(); res.next() )
531
+ {
532
+ String strAttrib = res.getStringByIdx(0);
533
+ String strObject = res.getStringByIdx(1);
534
+ String value = res.getStringByIdx(2);
535
+ String attribType = res.getStringByIdx(3);
536
+
537
+ if ( m_hashIgnorePushObjects.containsKey(strObject) || strObject.length() == 0 )
538
+ continue;
539
+
540
+ if ( attribType.compare("blob.file") == 0 && value.length() > 0 )
541
+ {
542
+ CMultipartItem* pItem = new CMultipartItem();
543
+ CMultipartItem& oItem = *pItem;
544
+ oItem.m_strFilePath = RHODESAPPBASE().resolveDBFilesPath(value);
545
+ oItem.m_strContentType = "application/octet-stream";
546
+ oItem.m_strName = strAttrib + "-" + strObject;
547
+
548
+ if ( m_arBlobAttrs.indexOf(strAttrib) == -1 )
549
+ m_arBlobAttrs.addElement(strAttrib);
550
+
551
+ m_arMultipartItems.addElement(pItem);
552
+ }
553
+
554
+ if ( strBody.length() == 0 )
555
+ {
556
+ if ( !isSync )
557
+ strBody += "{";
558
+ else
559
+ strBody += "\"" + strUpdateType + "\":{";
560
+ }
561
+
562
+ if ( strObject.compare(strCurObject) != 0 )
563
+ {
564
+ if ( strCurObject.length() > 0 )
565
+ {
566
+ if ( !bFirst )
567
+ strBody += "}";
568
+ strBody += ",";
569
+ }
570
+
571
+ bFirst = true;
572
+ strBody += CJSONEntry::quoteValue(strObject);
573
+ strCurObject = strObject;
574
+ }
575
+
576
+ if (!bFirst)
577
+ strBody += ",";
578
+
579
+ if ( strAttrib.length() > 0 )
580
+ {
581
+ if ( bFirst )
582
+ strBody += ":{";
583
+
584
+ strBody += CJSONEntry::quoteValue(strAttrib) + ":" + CJSONEntry::quoteValue(value);
585
+ bFirst = false;
586
+ }
587
+ }
588
+
589
+ if ( strBody.length() > 0 )
590
+ {
591
+ if ( !bFirst )
592
+ strBody += "}";
593
+
594
+ strBody += "}";
595
+ }
596
+
597
+ if ( isSync )
598
+ getDB().executeSQL("UPDATE changed_values SET sent=1 WHERE source_id=? and update_type=? and sent=0", getID(), strUpdateType.c_str() );
599
+
600
+ getDB().Unlock();
601
+ }
602
+
603
+ void CSyncSource::applyChangedValues()
604
+ {
605
+ String strBody = "";
606
+ makePushBody_Ver3(strBody, "create", false);
607
+ if ( strBody.length() > 0 )
608
+ {
609
+ CJSONEntry oEntry(strBody.c_str());
610
+ processSyncCommand("insert", oEntry, false );
611
+ }
612
+
613
+ strBody = "";
614
+ makePushBody_Ver3(strBody, "delete", false);
615
+ if ( strBody.length() > 0 )
616
+ {
617
+ CJSONEntry oEntry(strBody.c_str());
618
+ processSyncCommand("delete", oEntry, false );
619
+ }
620
+
621
+ strBody = "";
622
+ makePushBody_Ver3(strBody, "update", false);
623
+ if ( strBody.length() > 0 )
624
+ {
625
+ CJSONEntry oEntry(strBody.c_str());
626
+ processSyncCommand("insert", oEntry, false );
627
+ }
628
+ }
629
+
630
+ void CSyncSource::syncServerChanges()
631
+ {
632
+ LOG(INFO) + "Sync server changes source ID :" + getID();
633
+
634
+ while( getSync().isContinueSync() &&
635
+ ( m_nErrCode == RhoAppAdapter.ERR_NONE || m_nErrCode == RhoAppAdapter.ERR_CUSTOMSYNCSERVER) )
636
+ {
637
+ setCurPageCount(0);
638
+ String strUrl = getProtocol().getServerQueryUrl(getName(), getSync().getClientID(), getSync().getSyncPageSize());
639
+ Hashtable<String, String> reqHeaders;
640
+ reqHeaders.put(getProtocol().getClientIDHeader(), getSync().getClientID());
641
+
642
+ if ( !m_bTokenFromDB && getToken() > 1 )
643
+ strUrl += "&token=" + convertToStringA(getToken());
644
+
645
+ if ( m_strQueryParams.length() > 0 )
646
+ strUrl += "&" + m_strQueryParams;
647
+
648
+ LOG(INFO) + "Pull changes from server. Url: " + strUrl;
649
+ PROF_START("Net");
650
+ NetResponse resp = getNet().doRequest("GET", strUrl, "", &getSync(), &reqHeaders);
651
+ PROF_STOP("Net");
652
+
653
+ if ( !resp.isOK() )
654
+ {
655
+ //getSync().stopSync();
656
+ m_nErrCode = RhoAppAdapter.getErrorFromResponse(resp);
657
+ m_strError = resp.getCharData();
658
+ continue;
659
+ }
660
+
661
+ const char* szData = null;
662
+ String strTestResp = getSync().getSourceOptions().getProperty(getID(), "rho_server_response");
663
+ if ( strTestResp.length() > 0 )
664
+ {
665
+ szData = strTestResp.c_str();
666
+ getNotify().setFakeServerResponse(true);
667
+ }
668
+ else
669
+ szData = resp.getCharData();
670
+
671
+ //LOG(INFO) + szData;
672
+ PROF_START("Parse");
673
+ CJSONArrayIterator oJsonArr(szData);
674
+ PROF_STOP("Parse");
675
+
676
+ processServerResponse_ver3(oJsonArr);
677
+
678
+ if (getSync().getSourceOptions().getBoolProperty(getID(), "pass_through"))
679
+ processToken(0);
680
+
681
+ if ( getToken() == 0 )
682
+ break;
683
+
684
+ if ( strTestResp.length() > 0 )
685
+ break;
686
+ }
687
+
688
+ if ( getSync().isSchemaChanged() )
689
+ getSync().stopSync();
690
+ }
691
+
692
+ //{"create-error":{"0_broken_object_id":{"name":"wrongname","an_attribute":"error create"},"0_broken_object_id-error":{"message":"error create"}}}
693
+ void CSyncSource::processServerErrors(CJSONEntry& oCmds)
694
+ {
695
+ Hashtable<String, String> errors;
696
+
697
+ const char* arErrTypes[] = {"source-error", "search-error", "create-error", "update-error", "delete-error", "update-rollback", null};
698
+ for( int i = 0; ; i++ )
699
+ {
700
+ if ( arErrTypes[i] == null )
701
+ break;
702
+ if ( !oCmds.hasName(arErrTypes[i]) )
703
+ continue;
704
+
705
+ String strServerError = "";
706
+
707
+ CJSONEntry errSrc = oCmds.getEntry(arErrTypes[i]);
708
+
709
+ String errorType = "";
710
+ CJSONStructIterator errIter(errSrc);
711
+
712
+ if ( i == 0 || i == 1 )//"source-error", "search-error"
713
+ {
714
+ if ( errIter.getCurValue().hasName("message") ) {
715
+ errorType = errIter.getCurKey() + "-json";
716
+ strServerError = String("{\"message\":\"")+errIter.getCurValue().getString("message")+"\"}";
717
+ }
718
+ } else {
719
+ //"create-error", "update-error", "delete-error", "update-rollback"
720
+ errorType = String(arErrTypes[i]) + "-json";
721
+
722
+ Hashtable<String,String> objErrors;
723
+
724
+ //iterate objects
725
+ for( ; !errIter.isEnd(); errIter.next() )
726
+ {
727
+ String strObject = errIter.getCurKey();
728
+
729
+ if ( String_endsWith(strObject, "-error") )
730
+ {
731
+ strObject = strObject.substr(0, strObject.length()-6);
732
+ }
733
+
734
+ String strValue = objErrors.get(strObject);
735
+
736
+ if ( strValue.length() == 0 ) {
737
+ strValue = "{";
738
+ }
739
+
740
+ if ( String_endsWith(strValue, "}") ) {
741
+ strValue = strValue.substr(0,strValue.length()-1);
742
+ }
743
+
744
+ if ( errIter.getCurValue().hasName("message") )
745
+ {
746
+ if (strValue.length() > 1) {
747
+ strValue += ",";
748
+ }
749
+ strValue += String("\"message\":\"") + errIter.getCurValue().getString("message") + "\"";
750
+ } else {
751
+ CJSONStructIterator attrIter(errIter.getCurValue());
752
+ bool first = true;
753
+ String strAttrs = "";
754
+ if ( !attrIter.isEnd() ) {
755
+ strAttrs += "\"attributes\":{";
756
+ }
757
+
758
+ for( ; !attrIter.isEnd(); attrIter.next() ) {
759
+ if ( first ) {
760
+ first = false;
761
+ } else {
762
+ strAttrs += ",";
763
+ }
764
+
765
+ String strAttrName = attrIter.getCurKey();
766
+ String strAttrValue = attrIter.getCurString();
767
+
768
+ strAttrs += "\""+strAttrName+"\":\""+strAttrValue+"\"";
769
+ }
770
+
771
+ if ( strAttrs.length() > 0 ) {
772
+ strAttrs += "}";
773
+ }
774
+
775
+ if ( strValue.length() > 1 ) {
776
+ strValue += ",";
777
+ }
778
+
779
+ strValue += strAttrs;
780
+ }
781
+
782
+ strValue += "}";
783
+
784
+ objErrors.put(strObject,strValue);
785
+
786
+ }
787
+
788
+ if ( objErrors.size() > 0 ) {
789
+ rho::String strObjects = "";
790
+ for ( Hashtable<String,String>::const_iterator it = objErrors.begin(); it != objErrors.end(); ++it ) {
791
+ if ( strObjects.size() > 0 ) {
792
+ strObjects += ",";
793
+ }
794
+ strObjects += "\"" + it->first + "\":" + it->second;
795
+ }
796
+ strServerError = rho::String("{") + strObjects + "}";
797
+ }
798
+ }
799
+
800
+
801
+ if ( (errorType.length()>0) && (strServerError.size()>0) ) {
802
+ errors.put(errorType,strServerError);
803
+ }
804
+
805
+
806
+ }
807
+
808
+ if ( errors.size() > 0 ) {
809
+ getNotify().fireSyncNotification2(this, true, RhoAppAdapter.ERR_CUSTOMSYNCSERVER, errors);
810
+ }
811
+ }
812
+
813
+ void CSyncSource::processServerResponse_ver3(CJSONArrayIterator& oJsonArr, bool isRecoveryMode )
814
+ {
815
+ PROF_START("Data1");
816
+
817
+ if ( oJsonArr.isEnd() )
818
+ {
819
+ getSync().stopSync();
820
+ m_nErrCode = RhoAppAdapter.ERR_UNEXPECTEDSERVERRESPONSE;
821
+ return;
822
+ }
823
+
824
+ int nVersion = 0;
825
+ if ( !oJsonArr.isEnd() && oJsonArr.getCurItem().hasName("version") )
826
+ {
827
+ nVersion = oJsonArr.getCurItem().getInt("version");
828
+ oJsonArr.next();
829
+ }
830
+
831
+ if ( nVersion != getProtocol().getVersion() )
832
+ {
833
+ LOG(ERROR) + "Sync server send data with incompatible version. Client version: " + convertToStringA(getProtocol().getVersion()) +
834
+ "; Server response version: " + convertToStringA(nVersion) + ". Source name: " + getName();
835
+ getSync().stopSync();
836
+ m_nErrCode = RhoAppAdapter.ERR_SYNCVERSION;
837
+ return;
838
+ }
839
+
840
+ if ( !oJsonArr.isEnd() && oJsonArr.getCurItem().hasName("token"))
841
+ {
842
+ processToken(oJsonArr.getCurItem().getUInt64("token"));
843
+ oJsonArr.next();
844
+ }
845
+
846
+ if ( !oJsonArr.isEnd() && oJsonArr.getCurItem().hasName("source") )
847
+ {
848
+ //skip it. it uses in search only
849
+ oJsonArr.next();
850
+ }
851
+
852
+ if ( !oJsonArr.isEnd() && oJsonArr.getCurItem().hasName("count") )
853
+ {
854
+ setCurPageCount(oJsonArr.getCurItem().getInt("count"));
855
+ oJsonArr.next();
856
+ }
857
+
858
+ if ( !oJsonArr.isEnd() && oJsonArr.getCurItem().hasName("refresh_time") )
859
+ {
860
+ setRefreshTime(oJsonArr.getCurItem().getInt("refresh_time"));
861
+ oJsonArr.next();
862
+ }
863
+
864
+ if ( !oJsonArr.isEnd() && oJsonArr.getCurItem().hasName("progress_count") )
865
+ {
866
+ //TODO: progress_count
867
+ //setTotalCount(oJsonArr.getCurItem().getInt("progress_count"));
868
+ oJsonArr.next();
869
+ }
870
+
871
+ if ( !oJsonArr.isEnd() && oJsonArr.getCurItem().hasName("total_count") )
872
+ {
873
+ setTotalCount(oJsonArr.getCurItem().getInt("total_count"));
874
+ oJsonArr.next();
875
+ }
876
+
877
+ //if ( getServerObjectsCount() == 0 )
878
+ // getNotify().fireSyncNotification(this, false, RhoAppAdapter.ERR_NONE, "");
879
+
880
+ if ( getToken() == 0 )
881
+ {
882
+ //oo conflicts
883
+ getDB().executeSQL("DELETE FROM changed_values where source_id=? and sent>=3", getID() );
884
+ //
885
+
886
+ }
887
+
888
+ LOG(INFO) + "Got " + getCurPageCount() + "(Processed: " + getServerObjectsCount() + ") records of " + getTotalCount() + " from server. Source: " + getName()
889
+ + ". Version: " + nVersion;
890
+
891
+ PROF_STOP("Data1");
892
+ if ( !oJsonArr.isEnd() && getSync().isContinueSync() )
893
+ {
894
+ CJSONEntry oCmds = oJsonArr.getCurItem();
895
+ PROF_START("Data");
896
+ //TODO: use isUIWaitDB inside processSyncCommand
897
+ // if ( getDB().isUIWaitDB() )
898
+ // {
899
+ // LOG(INFO) + "Commit transaction because of UI request.";
900
+ // getDB().endTransaction();
901
+ // getDB().startTransaction();
902
+ // }
903
+
904
+ if ( oCmds.hasName("schema-changed") )
905
+ {
906
+ getSync().setSchemaChanged(true);
907
+ }else
908
+ {
909
+ processServerErrors(oCmds);
910
+
911
+ getDB().startTransaction();
912
+
913
+ LOG(INFO) + "SyncSource: pass_through = " + getSync().getSourceOptions().getBoolProperty(getID(), "pass_through");
914
+ if (getSync().getSourceOptions().getBoolProperty(getID(), "pass_through"))
915
+ {
916
+ if ( m_bSchemaSource )
917
+ getDB().executeSQL( (String("DELETE FROM ") + getName()).c_str() );
918
+ else
919
+ getDB().executeSQL("DELETE FROM object_values WHERE source_id=?", getID() );
920
+ }
921
+
922
+ if ( oCmds.hasName("metadata") && getSync().isContinueSync() )
923
+ {
924
+ String strMetadata = oCmds.getString("metadata");
925
+ getDB().executeSQL("UPDATE sources SET metadata=? WHERE source_id=?", strMetadata, getID() );
926
+ }
927
+ if ( oCmds.hasName("links") && getSync().isContinueSync() )
928
+ processSyncCommand("links", oCmds.getEntry("links"), true );
929
+ if ( oCmds.hasName("delete") && getSync().isContinueSync() )
930
+ processSyncCommand("delete", oCmds.getEntry("delete"), true );
931
+ if ( oCmds.hasName("insert") && getSync().isContinueSync() )
932
+ processSyncCommand("insert", oCmds.getEntry("insert"), true );
933
+
934
+ PROF_STOP("Data");
935
+
936
+ PROF_START("DB");
937
+ getDB().endTransaction();
938
+ PROF_STOP("DB");
939
+
940
+ if (!isRecoveryMode) {
941
+ getNotify().fireObjectsNotification();
942
+ }
943
+ }
944
+ }
945
+
946
+ PROF_START("Data1");
947
+ if ( getCurPageCount() > 0 ) {
948
+ if ( !isRecoveryMode ) {
949
+ getNotify().fireSyncNotification(this, false, RhoAppAdapter.ERR_NONE, "");
950
+ }
951
+ }
952
+ PROF_STOP("Data1");
953
+ }
954
+
955
+
956
+ int CSyncSource::propertyBagInsertAndUpdate(const String& tableName, const String& to, json::CJSONEntry oCmdEntry, boolean bCheckUIRequest, rho::Hashtable<String, bool>& changedObjects)
957
+ {
958
+ // parse freesed props
959
+ rho::Hashtable<String, bool> freezedProps;
960
+ makeFreezedPropsHash(freezedProps);
961
+
962
+ bool should_check_props = bCheckUIRequest && (freezedProps.size() > 0);
963
+
964
+ // create temp table for inserting new data
965
+ getDB().executeSQL((String("DROP TABLE IF EXISTS ") + tableName).c_str());
966
+ getDB().executeSQL((String("CREATE TEMP TABLE ") + tableName + " ( "
967
+ "\"source_id\" BIGINT default NULL, "
968
+ "\"attrib\" varchar(255) default NULL, "
969
+ "\"object\" varchar(255) default NULL, "
970
+ "\"value\" varchar default NULL);").c_str());
971
+
972
+ // fill data using server JSON reply
973
+ CJSONStructIterator objIter(oCmdEntry);
974
+ int inserted = 0;
975
+ for( ; !objIter.isEnd() && getSync().isContinueSync(); objIter.next() )
976
+ {
977
+ String strObject = objIter.getCurKey();
978
+ CJSONStructIterator attrIter( objIter.getCurValue() );
979
+
980
+ bool was_changed = false;
981
+
982
+ for( ; !attrIter.isEnd(); attrIter.next() )
983
+ {
984
+ CAttrValue oAttrValue(attrIter.getCurKey(),attrIter.getCurString());
985
+
986
+ if ( should_check_props && !freezedProps.containsKey(oAttrValue.m_strAttrib)) {
987
+ LOG(INFO) + "Skip Non-exist property : " + oAttrValue.m_strAttrib + ". For model : " + getName();
988
+ continue;
989
+ }
990
+
991
+ if ( !processBlob("insert",strObject,oAttrValue) )
992
+ continue;
993
+
994
+ getDB().executeSQL((String("INSERT INTO ") + tableName +
995
+ "(attrib, source_id, object, value) VALUES(?,?,?,?)").c_str(),
996
+ oAttrValue.m_strAttrib, getID(), strObject, oAttrValue.m_strValue );
997
+
998
+ ++inserted;
999
+
1000
+ was_changed = true;
1001
+ }
1002
+
1003
+ if (was_changed)
1004
+ {
1005
+ changedObjects[strObject] = true;
1006
+ }
1007
+ }
1008
+ // index changes
1009
+ getDB().executeSQL((String("CREATE UNIQUE INDEX idx_") + tableName + " ON " + tableName + "(\"object\", \"attrib\", \"source_id\");").c_str());
1010
+
1011
+ // find conflicts when source_id, object and attrib are same but values differ
1012
+ IDBResult conflicts = getDB().executeSQL(
1013
+ (String("SELECT ") +
1014
+ tableName+".value, " + tableName+".object, "+ tableName + ".attrib, " + tableName + ".source_id "
1015
+ " FROM "+tableName+" , " + to +
1016
+ " WHERE " +
1017
+ to+".source_id="+tableName+".source_id AND " +
1018
+ to+".object="+tableName+".object AND " +
1019
+ to+".attrib="+tableName+".attrib AND " +
1020
+ to+".value!="+tableName+".value;").c_str());
1021
+
1022
+ // writeback conflicts
1023
+ while (!conflicts.isEnd())
1024
+ {
1025
+ if ( getSyncType().compare("none") != 0 )
1026
+ {
1027
+ // oo conflicts
1028
+ getDB().executeSQL("UPDATE changed_values SET sent=4 where object=? and attrib=? and source_id=? and update_type=? and sent>1",
1029
+ conflicts.getStringByIdx(1), conflicts.getStringByIdx(2), conflicts.getIntByIdx(3), "create" );
1030
+ //
1031
+ }
1032
+ conflicts.next();
1033
+ }
1034
+
1035
+ // update destination table
1036
+ IDBResult res = getDB().executeSQL((String("INSERT OR REPLACE INTO ") + to + " SELECT * FROM " + tableName).c_str());
1037
+
1038
+ getDB().executeSQL((String("DROP TABLE ") + tableName).c_str());
1039
+
1040
+ if ( getSyncType().compare("none") != 0 )
1041
+ {
1042
+ for(rho::Hashtable<String, bool>::const_iterator iter = changedObjects.begin(); iter!=changedObjects.end(); ++iter)
1043
+ {
1044
+ getNotify().onObjectChanged(getID(),iter->first, CSyncNotify::enUpdate);
1045
+ }
1046
+ }
1047
+
1048
+ m_nInserted += inserted;
1049
+
1050
+ return inserted;
1051
+ }
1052
+
1053
+ void CSyncSource::processSyncCommand(const String& strCmd, CJSONEntry oCmdEntry, boolean bCheckUIRequest)
1054
+ {
1055
+ CJSONStructIterator objIter(oCmdEntry);
1056
+
1057
+ if ( m_bSchemaSource ) {
1058
+ for( ; !objIter.isEnd() && getSync().isContinueSync(); objIter.next() )
1059
+ {
1060
+ String strObject = objIter.getCurKey();
1061
+ CJSONStructIterator attrIter( objIter.getCurValue() );
1062
+
1063
+ processServerCmd_Ver3_Schema(strCmd,strObject,attrIter,bCheckUIRequest);
1064
+
1065
+ if ( getSyncType().compare("none") == 0 )
1066
+ continue;
1067
+
1068
+ if ( bCheckUIRequest )
1069
+ {
1070
+ if ( getDB().isUIWaitDB() )
1071
+ {
1072
+ LOG(INFO) + "Commit transaction because of UI request.";
1073
+ getDB().endTransaction();
1074
+
1075
+ checkProgressStepNotify(false);
1076
+
1077
+ CSyncThread::getInstance()->sleep(1000);
1078
+ getDB().startTransaction();
1079
+ }else
1080
+ checkProgressStepNotify(true);
1081
+ }
1082
+ }
1083
+
1084
+ } else {
1085
+ if (strCmd == "insert")
1086
+ {
1087
+ // batch insertions
1088
+ rho::Hashtable<String, bool> changedObjects;
1089
+ propertyBagInsertAndUpdate("temp_insert", "object_values", oCmdEntry, bCheckUIRequest, changedObjects);
1090
+
1091
+ } else {
1092
+ for( ; !objIter.isEnd() && getSync().isContinueSync(); objIter.next() )
1093
+ {
1094
+ String strObject = objIter.getCurKey();
1095
+ CJSONStructIterator attrIter( objIter.getCurValue() );
1096
+
1097
+ for( ; !attrIter.isEnd(); attrIter.next() )
1098
+ {
1099
+ String strAttrib = attrIter.getCurKey();
1100
+ String strValue = attrIter.getCurString();
1101
+
1102
+ processServerCmd_Ver3(strCmd,strObject,strAttrib,strValue,bCheckUIRequest);
1103
+ }
1104
+
1105
+ if ( getSyncType().compare("none") == 0 )
1106
+ continue;
1107
+
1108
+ if ( bCheckUIRequest )
1109
+ {
1110
+ if ( getDB().isUIWaitDB() )
1111
+ {
1112
+ LOG(INFO) + "Commit transaction because of UI request.";
1113
+ getDB().endTransaction();
1114
+
1115
+ checkProgressStepNotify(false);
1116
+
1117
+ CSyncThread::getInstance()->sleep(1000);
1118
+ getDB().startTransaction();
1119
+ }
1120
+ else
1121
+ checkProgressStepNotify(true);
1122
+ }
1123
+ }
1124
+ }
1125
+ }
1126
+ }
1127
+
1128
+ void CSyncSource::checkProgressStepNotify(boolean bEndTransaction)
1129
+ {
1130
+ int nSyncObjectCount = getNotify().incLastSyncObjectCount(getID());
1131
+ if ( getProgressStep() > 0 && (nSyncObjectCount%getProgressStep() == 0) )
1132
+ {
1133
+ if ( bEndTransaction )
1134
+ {
1135
+ LOG(INFO) + "Commit transaction because of Sync Progress notification.";
1136
+ getDB().endTransaction();
1137
+ }
1138
+
1139
+ getNotify().fireSyncNotification(this, false, RhoAppAdapter.ERR_NONE, "");
1140
+
1141
+ if ( bEndTransaction )
1142
+ getDB().startTransaction();
1143
+ }
1144
+ }
1145
+
1146
+ void CSyncSource::processAssociations(const String& strOldObject, const String& strNewObject)
1147
+ {
1148
+ for ( int i = 0; i < (int)m_arAssociations.size(); i++ )
1149
+ {
1150
+ CSyncSource* pSrc = getSync().findSourceByName(m_arAssociations.elementAt(i).m_strSrcName);
1151
+ if ( pSrc != null )
1152
+ pSrc->updateAssociation(strOldObject, strNewObject, m_arAssociations.elementAt(i).m_strAttrib);
1153
+ }
1154
+ }
1155
+
1156
+ void CSyncSource::updateAssociation(const String& strOldObject, const String& strNewObject, const String& strAttrib)
1157
+ {
1158
+ if ( m_bSchemaSource )
1159
+ {
1160
+ String strSqlUpdate = "UPDATE ";
1161
+ strSqlUpdate += getName() + " SET " + strAttrib + "=? where " + strAttrib + "=?";
1162
+
1163
+ getDB().executeSQL(strSqlUpdate.c_str(), strNewObject, strOldObject );
1164
+ }
1165
+ else
1166
+ getDB().executeSQL("UPDATE object_values SET value=? where attrib=? and source_id=? and value=?",
1167
+ strNewObject, strAttrib, getID(), strOldObject );
1168
+
1169
+ getDB().executeSQL("UPDATE changed_values SET value=? where attrib=? and source_id=? and value=?",
1170
+ strNewObject, strAttrib, getID(), strOldObject );
1171
+ }
1172
+
1173
+ void CSyncSource::processServerCmd_Ver3_Schema(const String& strCmd, const String& strObject, CJSONStructIterator& attrIter, boolean bCheckUIRequest)//throws Exception
1174
+ {
1175
+ if ( strCmd.compare("insert") == 0 )
1176
+ {
1177
+ Vector<String> vecValues, vecAttrs;
1178
+ String strCols = "", strQuest = "", strSet = "";
1179
+ for( ; !attrIter.isEnd(); attrIter.next() )
1180
+ {
1181
+ CAttrValue oAttrValue(attrIter.getCurKey(),attrIter.getCurString());
1182
+
1183
+ if ( bCheckUIRequest && !checkFreezedProps(oAttrValue.m_strAttrib))
1184
+ continue;
1185
+
1186
+ if ( !processBlob(strCmd,strObject,oAttrValue) )
1187
+ break;
1188
+
1189
+ if ( strCols.length() > 0 )
1190
+ strCols += ",";
1191
+ if ( strQuest.length() > 0)
1192
+ strQuest += ",";
1193
+ if ( strSet.length() > 0)
1194
+ strSet += ",";
1195
+
1196
+ strCols += oAttrValue.m_strAttrib;
1197
+ strQuest += "?";
1198
+ strSet += oAttrValue.m_strAttrib + "=?";
1199
+ vecAttrs.addElement(oAttrValue.m_strAttrib);
1200
+ vecValues.addElement(oAttrValue.m_strValue);
1201
+ }
1202
+ vecValues.addElement(strObject);
1203
+ if ( strCols.length() > 0 )
1204
+ strCols += ",";
1205
+ if ( strQuest.length() > 0)
1206
+ strQuest += ",";
1207
+
1208
+ strCols += "object";
1209
+ strQuest += "?";
1210
+
1211
+ String strSqlInsert = "INSERT INTO ";
1212
+ strSqlInsert += getName() + " (";
1213
+ strSqlInsert += strCols + ") VALUES(" + strQuest + ")";
1214
+
1215
+ if ( !getSync().isContinueSync() )
1216
+ return;
1217
+
1218
+ IDBResult resInsert = getDB().executeSQLReportNonUniqueEx(strSqlInsert.c_str(), vecValues );
1219
+ if ( resInsert.isNonUnique() )
1220
+ {
1221
+ String strSqlUpdate = "UPDATE ";
1222
+ strSqlUpdate += getName() + " SET " + strSet + " WHERE object=?";
1223
+ getDB().executeSQLEx(strSqlUpdate.c_str(), vecValues);
1224
+
1225
+ if ( getSyncType().compare("none") != 0 )
1226
+ {
1227
+ // oo conflicts
1228
+ for( int i = 0; i < (int)vecAttrs.size(); i++ )
1229
+ {
1230
+ getDB().executeSQL("UPDATE changed_values SET sent=4 where object=? and attrib=? and source_id=? and update_type=? and sent>1",
1231
+ strObject, vecAttrs.elementAt(i), getID(), "create" );
1232
+ }
1233
+ //
1234
+ }
1235
+ }
1236
+
1237
+ if ( getSyncType().compare("none") != 0 )
1238
+ getNotify().onObjectChanged(getID(),strObject, CSyncNotify::enUpdate);
1239
+
1240
+ m_nInserted++;
1241
+ }else if (strCmd.compare("delete") == 0)
1242
+ {
1243
+ Vector<String> vecAttrs;
1244
+ String strSet = "";
1245
+ for( ; !attrIter.isEnd() && getSync().isContinueSync(); attrIter.next() )
1246
+ {
1247
+ CAttrValue oAttrValue(attrIter.getCurKey(),attrIter.getCurString());
1248
+
1249
+ if ( strSet.length() > 0 )
1250
+ strSet += ",";
1251
+
1252
+ vecAttrs.addElement(oAttrValue.m_strAttrib);
1253
+ strSet += oAttrValue.m_strAttrib + "=NULL";
1254
+ }
1255
+
1256
+ String strSqlUpdate = "UPDATE ";
1257
+ strSqlUpdate += getName() + " SET " + strSet + " WHERE object=?";
1258
+
1259
+ if ( strSet.length() == 0 )
1260
+ return;
1261
+
1262
+ getDB().executeSQL(strSqlUpdate.c_str(), strObject);
1263
+ //Remove item if all nulls
1264
+ String strSelect = String("SELECT * FROM ") + getName() + " WHERE object=?";
1265
+ IDBResult res = getDB().executeSQL( strSelect.c_str(), strObject );
1266
+ if ( !res.isEnd() )
1267
+ {
1268
+ boolean bAllNulls = true;
1269
+ for( int i = 0; i < res.getColCount(); i ++)
1270
+ {
1271
+ if ( !res.isNullByIdx(i) && res.getColName(i).compare("object")!=0 )
1272
+ {
1273
+ bAllNulls = false;
1274
+ break;
1275
+ }
1276
+ }
1277
+
1278
+ if (bAllNulls)
1279
+ {
1280
+ String strDelete = String("DELETE FROM ") + getName() + " WHERE object=?";
1281
+ getDB().executeSQL( strDelete.c_str(), strObject);
1282
+ }
1283
+ }
1284
+
1285
+ if ( getSyncType().compare("none") != 0 )
1286
+ {
1287
+ getNotify().onObjectChanged(getID(), strObject, CSyncNotify::enDelete);
1288
+ // oo conflicts
1289
+ for( int i = 0; i < (int)vecAttrs.size(); i++ )
1290
+ {
1291
+ getDB().executeSQL("UPDATE changed_values SET sent=3 where object=? and attrib=? and source_id=? and update_type=?",
1292
+ strObject, vecAttrs.elementAt(i), getID(), "create" );
1293
+ }
1294
+ //
1295
+ }
1296
+
1297
+ m_nDeleted++;
1298
+ }else if ( strCmd.compare("links") == 0 )
1299
+ {
1300
+ String strValue = attrIter.getCurString();
1301
+ processAssociations(strObject, strValue);
1302
+
1303
+ String strSqlUpdate = "UPDATE ";
1304
+ strSqlUpdate += getName() + " SET object=? WHERE object=?";
1305
+ getDB().executeSQL(strSqlUpdate.c_str(), strValue, strObject);
1306
+
1307
+ getDB().executeSQL("UPDATE changed_values SET object=?,sent=3 where object=? and source_id=? and update_type=?", strValue, strObject, getID(), "create" );
1308
+ getNotify().onObjectChanged(getID(), strObject, CSyncNotify::enCreate);
1309
+ }
1310
+
1311
+ }
1312
+
1313
+ boolean CSyncSource::processBlob( const String& strCmd, const String& strObject, CAttrValue& oAttrValue )
1314
+ {
1315
+ //TODO: when server return delete with rhoblob postfix - delete isBlobAttr
1316
+ if ( !(oAttrValue.m_strBlobSuffix.length() > 0 || getDB().getAttrMgr().isBlobAttr(getID(), oAttrValue.m_strAttrib.c_str())) )
1317
+ return true;
1318
+
1319
+ boolean bDownload = true;
1320
+ String strDbValue = "";
1321
+ if ( !getDB().getAttrMgr().isOverwriteBlobFromServer(getID(), oAttrValue.m_strAttrib) )
1322
+ {
1323
+ if ( m_bSchemaSource )
1324
+ {
1325
+ String strSelect = String("SELECT ") + oAttrValue.m_strAttrib + " FROM " + getName() + " WHERE object=?";
1326
+ IDBResult res = getDB().executeSQL( strSelect.c_str(), strObject);
1327
+ if (!res.isEnd())
1328
+ {
1329
+ strDbValue = res.getStringByIdx(0);
1330
+ bDownload = strDbValue.length() == 0;
1331
+ }
1332
+ }else
1333
+ {
1334
+ IDBResult res = getDB().executeSQL(
1335
+ "SELECT value FROM object_values WHERE object=? and attrib=? and source_id=?",
1336
+ strObject, oAttrValue.m_strAttrib, getID() );
1337
+ if (!res.isEnd())
1338
+ {
1339
+ strDbValue = res.getStringByIdx(0);
1340
+ bDownload = strDbValue.length() == 0;
1341
+ }
1342
+ }
1343
+ }
1344
+
1345
+ if ( bDownload )
1346
+ {
1347
+ getDB().endTransaction();
1348
+ boolean bRes = downloadBlob(oAttrValue);
1349
+ getDB().startTransaction();
1350
+
1351
+ return bRes;
1352
+ }
1353
+
1354
+ oAttrValue.m_strValue = strDbValue;
1355
+ return true;
1356
+ }
1357
+
1358
+ boolean CSyncSource::processServerBlobAttrs() {
1359
+ if ( m_bSchemaSource ) {
1360
+ return true;
1361
+ } else {
1362
+ static const String blobSfx = "-rhoblob";
1363
+
1364
+ getDB().startTransaction();
1365
+ IDBResult res = getDB().executeSQL( "SELECT source_attribs,blob_attribs from sources WHERE source_id=?", getID() );
1366
+
1367
+ Vector<String> attrsToRename;
1368
+
1369
+ String newAttrs = "";
1370
+
1371
+ for ( ; !res.isEnd(); res.next() )
1372
+ {
1373
+ String attrs = res.getStringByIdx(0);
1374
+ String blobs = res.getStringByIdx(1);
1375
+
1376
+ CTokenizer tokenizer(attrs,",");
1377
+ while (tokenizer.hasMoreTokens()) {
1378
+ String attrName = tokenizer.nextToken();
1379
+ if (!tokenizer.hasMoreTokens()) {
1380
+ break;
1381
+ }
1382
+ String attrVal = tokenizer.nextToken();
1383
+
1384
+
1385
+ if ( String_endsWith( attrName, blobSfx ) ) {
1386
+ if ( blobs.length() > 0 ) {
1387
+ blobs += ",";
1388
+ }
1389
+ blobs += attrName.substr(0,attrName.length()-blobSfx.length()) + "," + attrVal;
1390
+ attrsToRename.addElement(attrName);
1391
+ } else {
1392
+ if (newAttrs.length() > 0 ) {
1393
+ newAttrs += ",";
1394
+ }
1395
+ newAttrs += attrName + "," + attrVal;
1396
+ }
1397
+ }
1398
+
1399
+ LOG(TRACE) + "Updating attributes for source " + getName() + ". Old attribs=" + attrs + ", new attribs=" + newAttrs + ", blob attribs=" + blobs;
1400
+
1401
+ getDB().executeSQL("UPDATE sources SET source_attribs=?,blob_attribs=? WHERE source_id=?", newAttrs, blobs, getID() );
1402
+ }
1403
+
1404
+ for ( int i = 0; i < (int)attrsToRename.size(); i++ )
1405
+ {
1406
+ String strAttr = (String)attrsToRename.elementAt(i);
1407
+ LOG(TRACE) + "Updating objects with blob attribute " + strAttr + " for source " + getName();
1408
+ getDB().executeSQL( "UPDATE object_values SET attrib=? WHERE attrib=? and source_id=?", strAttr.substr( 0, strAttr.length()-blobSfx.length()), strAttr, getID() );
1409
+ }
1410
+
1411
+ getDB().endTransaction();
1412
+ }
1413
+ return true;
1414
+ }
1415
+
1416
+
1417
+ boolean CSyncSource::processAllBlobs()
1418
+ {
1419
+ if (m_bSchemaSource) {
1420
+ Vector<String> blobAttrs = getDB().getAttrMgr().getBlobAttrs( getID() );
1421
+
1422
+ for ( int i = 0; i < (int)blobAttrs.size(); i ++ )
1423
+ {
1424
+ String strAttr = (String)blobAttrs.elementAt(i);
1425
+ String sql = "SELECT object," + strAttr + " FROM " + getName();
1426
+
1427
+ IDBResult res = getDB().executeSQL( sql.c_str() );
1428
+
1429
+ LOG(TRACE) + "Processing blobs for source " + getName() + ", attribute " + strAttr;
1430
+
1431
+ for ( ; !res.isEnd(); res.next() )
1432
+ {
1433
+ String object = res.getStringByIdx(0);
1434
+ String value = res.getStringByIdx(1);
1435
+
1436
+ if ( value.find("://") != String::npos ) {
1437
+ LOG(TRACE) + "Processing remote blob: " + value;
1438
+ CAttrValue attr( strAttr, value );
1439
+ if ( !downloadBlob( attr ) ) {
1440
+ return false;
1441
+ }
1442
+
1443
+ sql = "UPDATE " + getName() + " SET " + strAttr + "=? WHERE object=?";
1444
+
1445
+ getDB().executeSQL( sql.c_str(), attr.m_strValue, object );
1446
+ }
1447
+ }
1448
+ }
1449
+ } else {
1450
+ Vector<String> blobAttrs = getDB().getAttrMgr().getBlobAttrs( getID() );
1451
+
1452
+ for ( int i = 0; i < (int)blobAttrs.size(); i ++ )
1453
+ {
1454
+ String strAttr = (String)blobAttrs.elementAt(i);
1455
+ IDBResult res = getDB().executeSQL("SELECT object,value FROM object_values WHERE attrib=? and source_id=?", strAttr, getID());
1456
+
1457
+ LOG(TRACE) + "Processing blobs for source " + getName() + ", attribute " + strAttr;
1458
+
1459
+ for ( ; !res.isEnd(); res.next() )
1460
+ {
1461
+ String object = res.getStringByIdx(0);
1462
+ String value = res.getStringByIdx(1);
1463
+
1464
+ if ( value.find("://") != String::npos ) {
1465
+ LOG(TRACE) + "Processing remote blob: " + value;
1466
+ CAttrValue attr( strAttr, value );
1467
+ if ( !downloadBlob( attr ) ) {
1468
+ return false;
1469
+ }
1470
+
1471
+ getDB().executeSQL("UPDATE object_values SET value=? where object=? and source_id=? and attrib=?", attr.m_strValue, object, getID(), strAttr);
1472
+ }
1473
+ }
1474
+ }
1475
+ }
1476
+
1477
+ return true;
1478
+ }
1479
+
1480
+ boolean CSyncSource::checkFreezedProps(String strProp)
1481
+ {
1482
+ String strFreezedProps = getSync().getSourceOptions().getProperty(getID(), "freezed");
1483
+
1484
+ if ( strFreezedProps.length() > 0 )
1485
+ {
1486
+ CTokenizer oTokenizer( strFreezedProps, "," );
1487
+ boolean bFound =false;
1488
+ while (oTokenizer.hasMoreTokens() && (!bFound) )
1489
+ {
1490
+ String tok = oTokenizer.nextToken();
1491
+ if (tok.length() == 0)
1492
+ continue;
1493
+
1494
+ if (tok.compare(strProp)==0)
1495
+ {
1496
+ bFound = true;
1497
+ }
1498
+ }
1499
+
1500
+ if (!bFound)
1501
+ {
1502
+ LOG(INFO) + "Skip Non-exist property : " + strProp + ". For model : " + getName();
1503
+ return false;
1504
+ }
1505
+ }
1506
+
1507
+ return true;
1508
+ }
1509
+
1510
+ void CSyncSource::makeFreezedPropsHash(rho::Hashtable<String, bool>& hash)
1511
+ {
1512
+ hash.clear();
1513
+
1514
+ String strFreezedProps = getSync().getSourceOptions().getProperty(getID(), "freezed");
1515
+
1516
+ if ( strFreezedProps.length() > 0 )
1517
+ {
1518
+ CTokenizer oTokenizer( strFreezedProps, "," );
1519
+ while (oTokenizer.hasMoreTokens() )
1520
+ {
1521
+ String tok = oTokenizer.nextToken();
1522
+
1523
+ if (tok.length() == 0)
1524
+ continue;
1525
+
1526
+ hash[tok] = true;
1527
+ }
1528
+ }
1529
+ }
1530
+
1531
+ void CSyncSource::processServerCmd_Ver3(const String& strCmd, const String& strObject, const String& strAttriba, const String& strValuea, boolean bCheckUIRequest)//throws Exception
1532
+ {
1533
+ CAttrValue oAttrValue(strAttriba,strValuea);
1534
+
1535
+ if ( strCmd.compare("insert") == 0 )
1536
+ {
1537
+ if ( bCheckUIRequest && !checkFreezedProps(oAttrValue.m_strAttrib))
1538
+ return;
1539
+
1540
+ if ( !processBlob(strCmd,strObject,oAttrValue) )
1541
+ return;
1542
+
1543
+ IDBResult resInsert = getDB().executeSQLReportNonUnique("INSERT INTO object_values \
1544
+ (attrib, source_id, object, value) VALUES(?,?,?,?)",
1545
+ oAttrValue.m_strAttrib, getID(), strObject, oAttrValue.m_strValue );
1546
+ if ( resInsert.isNonUnique() )
1547
+ {
1548
+ getDB().executeSQL("UPDATE object_values \
1549
+ SET value=? WHERE object=? and attrib=? and source_id=?",
1550
+ oAttrValue.m_strValue, strObject, oAttrValue.m_strAttrib, getID() );
1551
+
1552
+ if ( getSyncType().compare("none") != 0 )
1553
+ {
1554
+ // oo conflicts
1555
+ getDB().executeSQL("UPDATE changed_values SET sent=4 where object=? and attrib=? and source_id=? and update_type=? and sent>1",
1556
+ strObject, oAttrValue.m_strAttrib, getID(), "create" );
1557
+ //
1558
+ }
1559
+ }
1560
+
1561
+ if ( getSyncType().compare("none") != 0 )
1562
+ getNotify().onObjectChanged(getID(),strObject, CSyncNotify::enUpdate);
1563
+
1564
+ m_nInserted++;
1565
+ }else if (strCmd.compare("delete") == 0)
1566
+ {
1567
+ getDB().executeSQL("DELETE FROM object_values where object=? and attrib=? and source_id=?", strObject, oAttrValue.m_strAttrib, getID() );
1568
+
1569
+ if ( getSyncType().compare("none") != 0 )
1570
+ {
1571
+ getNotify().onObjectChanged(getID(), strObject, CSyncNotify::enDelete);
1572
+ // oo conflicts
1573
+ getDB().executeSQL("UPDATE changed_values SET sent=3 where object=? and attrib=? and source_id=? and update_type=?", strObject, oAttrValue.m_strAttrib, getID(), "create" );
1574
+ //
1575
+ }
1576
+
1577
+ m_nDeleted++;
1578
+ }else if ( strCmd.compare("links") == 0 )
1579
+ {
1580
+ processAssociations(strObject, oAttrValue.m_strValue);
1581
+
1582
+ getDB().executeSQL("UPDATE object_values SET object=? where object=? and source_id=?", oAttrValue.m_strValue, strObject, getID() );
1583
+ getDB().executeSQL("UPDATE changed_values SET object=?,sent=3 where object=? and source_id=? and update_type=?", oAttrValue.m_strValue, strObject, getID(), "create" );
1584
+
1585
+ getNotify().onObjectChanged(getID(), strObject, CSyncNotify::enCreate);
1586
+ }
1587
+
1588
+ }
1589
+
1590
+ String CSyncSource::makeFileName(const CAttrValue& value)//throws Exception
1591
+ {
1592
+ String strExt = "";
1593
+
1594
+ URI uri(value.m_strValue);
1595
+ String strQuest = uri.getQueryString();
1596
+
1597
+ if (strQuest.length() > 0)
1598
+ {
1599
+ int nExt = strQuest.find("extension=");
1600
+ if ( nExt >= 0 )
1601
+ {
1602
+ int nExtEnd = strQuest.find("&", nExt);
1603
+ if (nExtEnd < 0 )
1604
+ nExtEnd = strQuest.length();
1605
+
1606
+ strExt = strQuest.substr(nExt+10, nExtEnd);
1607
+ }
1608
+ }
1609
+
1610
+ if ( strExt.length() == 0 )
1611
+ {
1612
+ String strFileName = uri.getLastNamePart();
1613
+ int nExt = strFileName.find_last_of('.');
1614
+ if ( nExt >= 0 )
1615
+ strExt = strFileName.substr(nExt);
1616
+ }
1617
+
1618
+ if ( strExt.length() == 0 )
1619
+ strExt = ".bin";
1620
+ else if ( strExt.at(0) != '.' )
1621
+ strExt = "." + strExt;
1622
+
1623
+ static int g_nBlobCounter = 0;
1624
+ String fName = RHODESAPPBASE().getBlobsDirPath() + "/id_" + CLocalTime().toString(true,true) + convertToStringA(g_nBlobCounter) + strExt;
1625
+ g_nBlobCounter++;
1626
+
1627
+ return fName;
1628
+ }
1629
+
1630
+ CAttrValue::CAttrValue(const String& strAttrib, const String& strValue)
1631
+ {
1632
+ m_strAttrib = strAttrib;
1633
+ m_strValue = strValue;
1634
+
1635
+ if ( String_endsWith(m_strAttrib,"-rhoblob") )
1636
+ {
1637
+ m_strBlobSuffix = "-rhoblob";
1638
+ m_strAttrib = m_strAttrib.substr(0,m_strAttrib.length()-m_strBlobSuffix.length());
1639
+ }
1640
+ }
1641
+
1642
+ boolean CSyncSource::downloadBlob(CAttrValue& value)//throws Exception
1643
+ {
1644
+ String fName = makeFileName( value );
1645
+ String url = value.m_strValue;
1646
+
1647
+ LOG(TRACE) + "Download blob: " + url + " => " + fName;
1648
+
1649
+ const char* nQuest = strchr(url.c_str(),'?');
1650
+ if ( nQuest > 0 )
1651
+ url += "&";
1652
+ else
1653
+ url += "?";
1654
+ url += "client_id=" + getSync().getClientID();
1655
+
1656
+ NetResponse resp = getNet().pullFile(url, fName, &getSync(), null, true, false);
1657
+ if ( !resp.isOK() )
1658
+ {
1659
+ CRhoFile::deleteFile(fName.c_str());
1660
+ //getSync().stopSync();
1661
+ m_nErrCode = RhoAppAdapter.getErrorFromResponse(resp);
1662
+ //m_strError = resp.getCharData();
1663
+ return false;
1664
+ }
1665
+
1666
+ value.m_strValue = RHODESAPPBASE().getRelativeDBFilesPath( fName );
1667
+
1668
+ return true;
1669
+ }
1670
+
1671
+ void CSyncSource::processToken(uint64 token)
1672
+ {
1673
+ if ( token > 1 && getToken() == token ){
1674
+ //Delete non-confirmed records
1675
+
1676
+ setToken( token ); //For m_bTokenFromDB = false;
1677
+ //getDB().executeSQL("DELETE FROM object_values where source_id=? and token=?", getID(), token );
1678
+ //TODO: add special table for id,token
1679
+ }else
1680
+ {
1681
+ setToken( token );
1682
+ getDB().executeSQL("UPDATE sources SET token=? where source_id=?", token, getID() );
1683
+ }
1684
+
1685
+ }
1686
+
1687
+ bool CSyncSource::haveChangedValues()
1688
+ {
1689
+ IDBResult res = getDB().executeSQL("SELECT object FROM changed_values WHERE source_id=? and sent<=1 LIMIT 1 OFFSET 0", getID());
1690
+ return !res.isEnd();
1691
+ }
1692
+
1693
+ }
1694
+ }