rhodes 1.5.4 → 1.5.5

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 (60) hide show
  1. data/Manifest.txt +11 -1
  2. data/Rakefile +1 -1
  3. data/lib/extensions/digest/ext/Rakefile +11 -6
  4. data/lib/extensions/digest/ext/build.bat +2 -0
  5. data/lib/extensions/uri/uri.rb +29 -0
  6. data/lib/extensions/uri/uri/common.rb +727 -0
  7. data/lib/extensions/uri/uri/ftp.rb +198 -0
  8. data/lib/extensions/uri/uri/generic.rb +1128 -0
  9. data/lib/extensions/uri/uri/http.rb +100 -0
  10. data/lib/extensions/uri/uri/https.rb +20 -0
  11. data/lib/extensions/uri/uri/ldap.rb +190 -0
  12. data/lib/extensions/uri/uri/ldaps.rb +12 -0
  13. data/lib/extensions/uri/uri/mailto.rb +266 -0
  14. data/lib/framework/rhodes.rb +2 -2
  15. data/lib/framework/rhom/rhom_db_adapter.rb +12 -26
  16. data/lib/framework/rhom/rhom_object_factory.rb +8 -1
  17. data/lib/framework/version.rb +2 -2
  18. data/lib/rhodes.rb +2 -2
  19. data/platform/android/Rhodes/AndroidManifest.xml +2 -2
  20. data/platform/android/Rhodes/src/com/rhomobile/rhodes/Rhodes.java +87 -42
  21. data/platform/android/Rhodes/src/com/rhomobile/rhodes/SplashScreen.java +58 -7
  22. data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/MainView.java +2 -0
  23. data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/SimpleMainView.java +35 -19
  24. data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/TabbedMainView.java +4 -0
  25. data/platform/android/build/android.rake +30 -25
  26. data/platform/bb/build/rhodes_build.files +1 -1
  27. data/platform/bb/rhodes/rhodes.jdp +1 -1
  28. data/platform/bb/rhodes/src/com/rho/RhoRubyHelper.java +1 -1
  29. data/platform/bb/rhodes/src/com/rho/rubyext/Alert.java +300 -0
  30. data/platform/bb/rhodes/src/com/rho/rubyext/GeoLocation.java +42 -5
  31. data/platform/bb/rhodes/src/rhomobile/PushListeningThread.java +3 -4
  32. data/platform/bb/rhodes/src/rhomobile/RhodesApplication.java +33 -107
  33. data/platform/iphone/Classes/RhoRunnerAppDelegate.m +2 -0
  34. data/platform/iphone/Info.plist +1 -1
  35. data/platform/iphone/rbuild/iphone.rake +1 -1
  36. data/platform/iphone/rhoextlib/rhoextlib.xcodeproj/project.pbxproj +4 -0
  37. data/platform/shared/common/RhoMutexLock.h +8 -1
  38. data/platform/shared/common/RhodesApp.cpp +1 -1
  39. data/platform/shared/db/DBAdapter.cpp +77 -8
  40. data/platform/shared/db/DBAdapter.h +24 -9
  41. data/platform/shared/db/DBResult.cpp +19 -0
  42. data/platform/shared/db/DBResult.h +7 -5
  43. data/platform/shared/net/HttpServer.cpp +2 -0
  44. data/platform/shared/ruby/ext/rho/rhoruby.c +55 -0
  45. data/platform/shared/ruby/ext/rho/rhoruby.h +9 -0
  46. data/platform/shared/ruby/ext/rho/rhosupport.c +13 -4
  47. data/platform/shared/ruby/ext/sqlite3_api/sqlite3_api_wrap.c +21 -0
  48. data/platform/shared/ruby/thread_pthread.c +4 -4
  49. data/platform/shared/ruby/thread_win32.c +4 -4
  50. data/platform/shared/rubyJVM/src/com/rho/RhodesApp.java +19 -1
  51. data/platform/shared/rubyJVM/src/com/rho/db/DBAdapter.java +57 -24
  52. data/platform/shared/rubyJVM/src/com/rho/net/NetRequest.java +6 -1
  53. data/platform/shared/rubyJVM/src/com/rho/sync/SyncSource.java +2 -2
  54. data/platform/shared/rubyJVM/src/com/rho/sync/SyncThread.java +5 -5
  55. data/platform/shared/sync/SyncSource.cpp +1 -1
  56. data/platform/shared/sync/SyncThread.cpp +6 -9
  57. data/platform/wm/rhodes/Rhodes.cpp +4 -0
  58. data/rakefile.rb +1 -1
  59. metadata +13 -3
  60. data/platform/bb/rhodes/src/rhomobile/Alert.java +0 -65
@@ -5,6 +5,22 @@
5
5
  #include "logging/RhoLog.h"
6
6
 
7
7
  namespace rho{
8
+ namespace common{
9
+ class CRubyMutex
10
+ {
11
+ int m_nLockCount;
12
+ unsigned long m_valThread, m_valMutex;
13
+
14
+ public:
15
+ CRubyMutex();
16
+ ~CRubyMutex();
17
+
18
+ boolean isMainRubyThread();
19
+ void Lock();
20
+ void Unlock();
21
+ };
22
+ }
23
+
8
24
  namespace db{
9
25
 
10
26
  class CDBAdapter
@@ -12,10 +28,10 @@ class CDBAdapter
12
28
  sqlite3* m_dbHandle;
13
29
  String m_strDbPath, m_strDbVer, m_strDbVerPath;
14
30
  Hashtable<String,sqlite3_stmt*> m_mapStatements;
31
+ common::CRubyMutex m_mxRuby;
15
32
  common::CMutex m_mxDB;
16
- common::CMutex m_mxTransDB;
17
- boolean m_bUnlockDB;
18
- boolean m_bInsideTransaction;
33
+ boolean m_bUIWaitDB;
34
+ int m_nTransactionCounter;
19
35
  CDBAttrManager m_attrMgr;
20
36
 
21
37
  struct CDBVersion
@@ -34,7 +50,7 @@ class CDBAdapter
34
50
  public:
35
51
  DEFINE_LOGCLASS;
36
52
 
37
- CDBAdapter(void) : m_dbHandle(0), m_strDbPath(""), m_bUnlockDB(false), m_bInsideTransaction(false){}
53
+ CDBAdapter(void) : m_dbHandle(0), m_strDbPath(""), m_bUIWaitDB(false), m_nTransactionCounter(0){}
38
54
  ~CDBAdapter(void){}
39
55
 
40
56
  void open (String strDbPath, String strVer, boolean bTemp);
@@ -42,11 +58,10 @@ public:
42
58
  sqlite3* getDbHandle(){ return m_dbHandle; }
43
59
  CDBAttrManager& getAttrMgr(){ return m_attrMgr; }
44
60
 
45
- boolean isUnlockDB()const{ return m_bUnlockDB; }
46
- void setUnlockDB(boolean b){ m_bUnlockDB = b; }
47
- void Lock(){ m_mxDB.Lock(); }
48
- void Unlock(){ setUnlockDB(false); m_mxDB.Unlock(); }
49
- boolean isInsideTransaction(){ return m_bInsideTransaction; }
61
+ boolean isUIWaitDB()const{ return m_bUIWaitDB; }
62
+ void Lock();
63
+ void Unlock();
64
+ boolean isInsideTransaction(){ return m_nTransactionCounter > 0; }
50
65
  const String& getDBPath(){ return m_strDbPath; }
51
66
 
52
67
  void bind(sqlite3_stmt* st, int nPos, int val)
@@ -1,11 +1,30 @@
1
1
  #include "DBResult.h"
2
+ #include "DBAdapter.h"
2
3
 
3
4
  namespace rho{
4
5
  namespace db{
5
6
 
7
+ CDBResult::CDBResult(sqlite3_stmt* st,CDBAdapter* pDB) : m_pDB(pDB), m_dbStatement(st)
8
+ {
9
+ m_bReportNonUnique=false;
10
+ m_nErrorCode=0;
11
+
12
+ if ( m_pDB )
13
+ m_pDB->Lock();
14
+ }
15
+
16
+ CDBResult::CDBResult() : m_pDB(null), m_dbStatement(null)
17
+ {
18
+ m_bReportNonUnique=false;
19
+ m_nErrorCode=0;
20
+ }
21
+
6
22
  CDBResult::~CDBResult(void)
7
23
  {
8
24
  setStatement(null);
25
+
26
+ if ( m_pDB )
27
+ m_pDB->Unlock();
9
28
  }
10
29
 
11
30
  void CDBResult::setStatement(sqlite3_stmt* st)
@@ -8,16 +8,18 @@
8
8
  namespace rho{
9
9
  namespace db{
10
10
 
11
+ class CDBAdapter;
12
+
11
13
  class CDBResult
12
14
  {
13
- common::CMutexLock m_lockDB;
15
+ //common::CMutexLock m_lockDB;
16
+ CDBAdapter* m_pDB;
14
17
  sqlite3_stmt* m_dbStatement;
15
18
  boolean m_bReportNonUnique;
16
19
  int m_nErrorCode;
17
20
  public:
18
- CDBResult(sqlite3_stmt* st,common::CMutex& mx) : m_lockDB(mx), m_dbStatement(st){m_bReportNonUnique=false;m_nErrorCode=0;}
19
- CDBResult(common::CMutex& mx) : m_lockDB(mx), m_dbStatement(null){m_bReportNonUnique=false;m_nErrorCode=0;}
20
-
21
+ CDBResult(sqlite3_stmt* st,CDBAdapter* pDB);
22
+ CDBResult();
21
23
  ~CDBResult(void);
22
24
 
23
25
  void setStatement(sqlite3_stmt* st);
@@ -52,7 +54,7 @@ public:
52
54
  return sqlite3_column_int64(m_dbStatement, nCol);
53
55
  }
54
56
  //private:
55
- CDBResult() : m_lockDB(*new common::CMutex() ){} //TEST ONLY
57
+ //CDBResult() : m_lockDB(*new common::CMutex() ){} //TEST ONLY
56
58
 
57
59
  };
58
60
 
@@ -340,7 +340,9 @@ bool CHttpServer::run()
340
340
 
341
341
  for(;;) {
342
342
  RAWTRACE("Waiting for connections...");
343
+ rho_ruby_start_threadidle();
343
344
  SOCKET conn = accept(m_listener, NULL, NULL);
345
+ rho_ruby_stop_threadidle();
344
346
  if (m_exit) {
345
347
  RAWTRACE("Stop HTTP server");
346
348
  return true;
@@ -99,6 +99,27 @@ void RhoRubyThreadStop()
99
99
  //native_mutex_destroy(&th->interrupt_lock);
100
100
  } */
101
101
 
102
+ extern int native_mutex_lock(rb_thread_lock_t *);
103
+ extern int native_mutex_unlock(rb_thread_lock_t *);
104
+
105
+ rb_thread_t * g_th_stored = 0;
106
+ void rho_ruby_start_threadidle()
107
+ {
108
+ g_th_stored = GET_THREAD();
109
+ rb_gc_save_machine_context(g_th_stored);
110
+ native_mutex_unlock(&g_th_stored->vm->global_vm_lock);
111
+ }
112
+
113
+ void rho_ruby_stop_threadidle()
114
+ {
115
+ if ( g_th_stored )
116
+ {
117
+ native_mutex_lock(&g_th_stored->vm->global_vm_lock);
118
+ rb_thread_set_current(g_th_stored);
119
+ g_th_stored = 0;
120
+ }
121
+ }
122
+
102
123
  void RhoRubyStart()
103
124
  {
104
125
  //VALUE moduleRhom;
@@ -390,6 +411,40 @@ void rho_ruby_releaseValue(VALUE val)
390
411
  rb_ary_delete_at(ary,i);
391
412
  }
392
413
 
414
+ extern VALUE rb_cMutex;
415
+ VALUE rho_ruby_create_mutex()
416
+ {
417
+ VALUE val = rb_funcall(rb_cMutex, rb_intern("new"), 0 );
418
+ rho_ruby_holdValue(val);
419
+
420
+ return val;
421
+ }
422
+
423
+ void rho_ruby_destroy_mutex(VALUE val)
424
+ {
425
+ rho_ruby_releaseValue(val);
426
+ }
427
+
428
+ void rho_ruby_lock_mutex(VALUE val)
429
+ {
430
+ rb_mutex_lock(val);
431
+ }
432
+
433
+ void rho_ruby_unlock_mutex(VALUE val)
434
+ {
435
+ rb_mutex_unlock(val);
436
+ }
437
+
438
+ VALUE rho_ruby_main_thread()
439
+ {
440
+ return rb_thread_main();
441
+ }
442
+
443
+ VALUE rho_ruby_current_thread()
444
+ {
445
+ return rb_thread_current();
446
+ }
447
+
393
448
  VALUE callFramework(VALUE hashReq) {
394
449
  VALUE callres = rb_funcall(framework, framework_mid, 1, hashReq);
395
450
 
@@ -36,6 +36,8 @@ void RhoRubyInitApp();
36
36
  //void RhoRubyThreadStart();
37
37
  //void RhoRubyThreadStop();
38
38
  void rho_ruby_activateApp();
39
+ void rho_ruby_start_threadidle();
40
+ void rho_ruby_stop_threadidle();
39
41
 
40
42
  VALUE createHash();
41
43
  VALUE addTimeToHash(VALUE hash, const char* key, time_t val);
@@ -84,6 +86,13 @@ const char* rho_ruby_getMessageText(const char* szName);
84
86
  const char* rho_ruby_getErrorText(int nError);
85
87
  const char* rho_ruby_internal_getErrorText(int nError);
86
88
 
89
+ VALUE rho_ruby_create_mutex();
90
+ void rho_ruby_destroy_mutex(VALUE val);
91
+ VALUE rho_ruby_main_thread();
92
+ VALUE rho_ruby_current_thread();
93
+ void rho_ruby_lock_mutex(VALUE val);
94
+ void rho_ruby_unlock_mutex(VALUE val);
95
+
87
96
  #if defined(__cplusplus)
88
97
  }
89
98
  #endif
@@ -11,6 +11,7 @@
11
11
  #endif
12
12
 
13
13
  #include "common/RhodesApp.h"
14
+ #include "common/RhoMutexLock.h"
14
15
  #include "logging/RhoLog.h"
15
16
  #undef DEFAULT_LOGCATEGORY
16
17
  #define DEFAULT_LOGCATEGORY "RhoRuby"
@@ -266,11 +267,15 @@ VALUE isAlreadyLoaded(VALUE path)
266
267
  return Qfalse;
267
268
  }
268
269
 
270
+ RHO_INIT_LOCK(require_lock);
271
+
269
272
  VALUE require_compiled(VALUE fname, VALUE* result)
270
273
  {
271
274
  VALUE path;
272
275
  char* szName1 = 0;
276
+ VALUE retval = Qtrue;
273
277
 
278
+ RHO_LOCK(require_lock);
274
279
  rb_funcall(fname, rb_intern("sub!"), 2, rb_str_new2(".rb"), rb_str_new2("") );
275
280
 
276
281
  szName1 = RSTRING_PTR(fname);
@@ -279,10 +284,10 @@ VALUE require_compiled(VALUE fname, VALUE* result)
279
284
  strcmp("digest.so",szName1)==0 ||
280
285
  strcmp("fcntl",szName1)==0 || strcmp("digest/md5",szName1)==0 ||
281
286
  strcmp("digest/sha1",szName1)==0 )
282
- return Qtrue;
287
+ goto RCompExit;
283
288
 
284
289
  if ( isAlreadyLoaded(fname) == Qtrue )
285
- return Qtrue;
290
+ goto RCompExit;
286
291
 
287
292
  //RAWLOG_INFO1("find_file: %s", RSTRING_PTR(fname));
288
293
  path = find_file(fname);
@@ -307,11 +312,15 @@ VALUE require_compiled(VALUE fname, VALUE* result)
307
312
  //*result = rb_funcall(seq, rb_intern("eval"), 0 );
308
313
  *result = rb_iseq_eval(seq);
309
314
 
310
- return Qtrue;
315
+ goto RCompExit;
311
316
  }
312
317
 
313
318
  RAWLOG_ERROR1("require_compiled: error: can not find %s", RSTRING_PTR(fname));
314
- return Qnil;
319
+ retval = Qnil;
320
+
321
+ RCompExit:
322
+ RHO_UNLOCK(require_lock);
323
+ return retval;
315
324
  }
316
325
 
317
326
  #ifndef CharNext /* defined as CharNext[AW] on Windows. */
@@ -14,6 +14,7 @@ extern int rho_db_startUITransaction();
14
14
  extern int rho_db_commitUITransaction();
15
15
  extern int rho_db_rollbackUITransaction();
16
16
  extern int rho_db_destroy_table(const char* szTableName);
17
+ extern int rho_db_is_ui_waitfordb();
17
18
  extern void* rho_db_get_handle();
18
19
 
19
20
  static VALUE db_allocate(VALUE klass)
@@ -134,6 +135,21 @@ static VALUE db_destroy_table(int argc, VALUE *argv, VALUE self)
134
135
  return INT2NUM(rc);
135
136
  }
136
137
 
138
+ static VALUE db_is_ui_waitfordb(int argc, VALUE *argv, VALUE self)
139
+ {
140
+ sqlite3 **ppDB = NULL;
141
+ int rc = 0;
142
+
143
+ if (argc > 0)
144
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 0)",argc);
145
+
146
+ Data_Get_Struct(self, sqlite3 *, ppDB);
147
+
148
+ rc = rho_db_is_ui_waitfordb();
149
+
150
+ return rc == 0 ? Qfalse : Qtrue;
151
+ }
152
+
137
153
  static VALUE db_execute(int argc, VALUE *argv, VALUE self)
138
154
  {
139
155
  sqlite3 * db = NULL;
@@ -194,6 +210,8 @@ static VALUE db_execute(int argc, VALUE *argv, VALUE self)
194
210
  }
195
211
  }
196
212
 
213
+ rho_sync_lock();
214
+
197
215
  while( (nRes=sqlite3_step(statement)) == SQLITE_ROW) {
198
216
  int nCount = sqlite3_data_count(statement);
199
217
  int nCol = 0;
@@ -242,6 +260,8 @@ static VALUE db_execute(int argc, VALUE *argv, VALUE self)
242
260
  if ( colNames )
243
261
  free(colNames);
244
262
 
263
+ rho_sync_unlock();
264
+
245
265
  return arRes;
246
266
  }
247
267
 
@@ -258,6 +278,7 @@ void Init_sqlite3_api(void)
258
278
  rb_define_method(mDatabase, "commit", db_commit, -1);
259
279
  rb_define_method(mDatabase, "rollback", db_rollback, -1);
260
280
  rb_define_method(mDatabase, "destroy_table", db_destroy_table, -1);
281
+ rb_define_method(mDatabase, "is_ui_waitfordb", db_is_ui_waitfordb, -1);
261
282
  }
262
283
 
263
284
  #if 0
@@ -17,8 +17,8 @@
17
17
  #include <sys/resource.h>
18
18
  #endif
19
19
 
20
- static void native_mutex_lock(pthread_mutex_t *lock);
21
- static void native_mutex_unlock(pthread_mutex_t *lock);
20
+ void native_mutex_lock(pthread_mutex_t *lock);
21
+ void native_mutex_unlock(pthread_mutex_t *lock);
22
22
  static int native_mutex_trylock(pthread_mutex_t *lock);
23
23
  void native_mutex_initialize(pthread_mutex_t *lock);
24
24
  void native_mutex_destroy(pthread_mutex_t *lock);
@@ -29,7 +29,7 @@ static void native_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
29
29
  static void native_cond_initialize(pthread_cond_t *cond);
30
30
  static void native_cond_destroy(pthread_cond_t *cond);
31
31
 
32
- static void
32
+ void
33
33
  native_mutex_lock(pthread_mutex_t *lock)
34
34
  {
35
35
  int r;
@@ -38,7 +38,7 @@ native_mutex_lock(pthread_mutex_t *lock)
38
38
  }
39
39
  }
40
40
 
41
- static void
41
+ void
42
42
  native_mutex_unlock(pthread_mutex_t *lock)
43
43
  {
44
44
  int r;
@@ -22,8 +22,8 @@
22
22
 
23
23
  static volatile DWORD ruby_native_thread_key = TLS_OUT_OF_INDEXES;
24
24
 
25
- static int native_mutex_lock(rb_thread_lock_t *);
26
- static int native_mutex_unlock(rb_thread_lock_t *);
25
+ int native_mutex_lock(rb_thread_lock_t *);
26
+ int native_mutex_unlock(rb_thread_lock_t *);
27
27
  static int native_mutex_trylock(rb_thread_lock_t *);
28
28
  void native_mutex_initialize(rb_thread_lock_t *);
29
29
 
@@ -251,7 +251,7 @@ native_sleep(rb_thread_t *th, struct timeval *tv)
251
251
  GVL_UNLOCK_END();
252
252
  }
253
253
 
254
- static int
254
+ int
255
255
  native_mutex_lock(rb_thread_lock_t *lock)
256
256
  {
257
257
  #if USE_WIN32_MUTEX
@@ -287,7 +287,7 @@ native_mutex_lock(rb_thread_lock_t *lock)
287
287
  #endif
288
288
  }
289
289
 
290
- static int
290
+ int
291
291
  native_mutex_unlock(rb_thread_lock_t *lock)
292
292
  {
293
293
  #if USE_WIN32_MUTEX
@@ -1,5 +1,6 @@
1
1
  package com.rho;
2
2
 
3
+ import com.rho.net.*;
3
4
  import com.xruby.runtime.lang.RubyValue;
4
5
  import java.util.Vector;
5
6
 
@@ -13,6 +14,8 @@ public class RhodesApp
13
14
  private String m_strRhoRootPath;
14
15
  Vector/*<unsigned long>*/ m_arCallbackObjects = new Vector();
15
16
  private SplashScreen m_oSplashScreen = new SplashScreen();
17
+
18
+ NetRequest getNet() { return RhoClassFactory.createNetRequest();}
16
19
 
17
20
  public static RhodesApp Create(String strRootPath)
18
21
  {
@@ -68,5 +71,20 @@ public class RhodesApp
68
71
  m_arCallbackObjects.setElementAt(null,nIndex);
69
72
  return res;
70
73
  }
71
-
74
+
75
+ String canonicalizeRhoUrl(String strUrl)throws Exception
76
+ {
77
+ return getNet().resolveUrl(strUrl);
78
+ }
79
+
80
+ public void callPopupCallback(String strCallbackUrl, String id, String title)throws Exception
81
+ {
82
+ if ( strCallbackUrl == null || strCallbackUrl.length() == 0 )
83
+ return;
84
+
85
+ strCallbackUrl = canonicalizeRhoUrl(strCallbackUrl);
86
+ String strBody = "button_id=" + id + "&button_title=" + title;
87
+ strBody += "&rho_callback=1";
88
+ getNet().pushData( strCallbackUrl, strBody, null );
89
+ }
72
90
  }
@@ -18,8 +18,8 @@ public class DBAdapter extends RubyBasic {
18
18
  private DBAttrManager m_attrMgr = new DBAttrManager();
19
19
 
20
20
  Mutex m_mxDB = new Mutex();
21
- boolean m_bInsideTransaction=false;
22
- boolean m_bUnlockDB = false;
21
+ int m_nTransactionCounter=0;
22
+ boolean m_bUIWaitDB = false;
23
23
 
24
24
  DBAdapter(RubyClass c) {
25
25
  super(c);
@@ -110,11 +110,11 @@ public class DBAdapter extends RubyBasic {
110
110
  return executeSQL(strStatement,values);
111
111
  }
112
112
 
113
- public boolean isUnlockDB(){ return m_bUnlockDB; }
114
- public void setUnlockDB(boolean b){ m_bUnlockDB = b; }
113
+ public boolean isUIWaitDB(){ return m_bUIWaitDB; }
114
+ public void setUIWaitDB(boolean b){ m_bUIWaitDB = b; }
115
115
  public void Lock(){ m_mxDB.Lock(); }
116
- public void Unlock(){ setUnlockDB(false); m_mxDB.Unlock(); }
117
- public boolean isInsideTransaction(){ return m_bInsideTransaction; }
116
+ public void Unlock(){ m_mxDB.Unlock(); }
117
+ public boolean isInsideTransaction(){ return m_nTransactionCounter>0; }
118
118
 
119
119
  public static IDBResult createResult(){
120
120
  return getInstance().m_dbStorage.createResult();
@@ -173,15 +173,22 @@ public class DBAdapter extends RubyBasic {
173
173
  public void startTransaction()throws DBException
174
174
  {
175
175
  Lock();
176
- m_bInsideTransaction=true;
177
- m_dbStorage.startTransaction();
176
+ m_nTransactionCounter++;
177
+
178
+ if (m_nTransactionCounter == 1)
179
+ m_dbStorage.startTransaction();
178
180
  }
179
181
 
180
182
  public void commit()throws DBException
181
183
  {
182
- getAttrMgr().save(this);
183
- m_dbStorage.commit();
184
- m_bInsideTransaction=false;
184
+ m_nTransactionCounter--;
185
+
186
+ if (m_nTransactionCounter == 0)
187
+ {
188
+ getAttrMgr().save(this);
189
+ m_dbStorage.commit();
190
+ }
191
+
185
192
  Unlock();
186
193
  }
187
194
  public void endTransaction()throws DBException
@@ -534,8 +541,10 @@ public class DBAdapter extends RubyBasic {
534
541
 
535
542
  public void rollback()throws DBException
536
543
  {
537
- m_dbStorage.rollback();
538
- m_bInsideTransaction=false;
544
+ m_nTransactionCounter--;
545
+
546
+ if (m_nTransactionCounter == 0)
547
+ m_dbStorage.rollback();
539
548
 
540
549
  Unlock();
541
550
  }
@@ -682,17 +691,28 @@ public class DBAdapter extends RubyBasic {
682
691
  }
683
692
  }
684
693
 
685
- IDBResult rows = executeSQL(v.toStr(), values);
686
- RubyString[] colNames = getColNames(rows);
694
+ setUIWaitDB(true);
695
+ Lock();
696
+
697
+ try{
698
+ IDBResult rows = executeSQL(v.toStr(), values);
699
+
700
+ RubyString[] colNames = getColNames(rows);
701
+
702
+ for( ; !rows.isEnd(); rows.next() )
703
+ {
704
+ RubyHash row = ObjectFactory.createHash();
705
+ for ( int nCol = 0; nCol < rows.getColCount(); nCol ++ )
706
+ row.add( colNames[nCol], rows.getRubyValueByIdx(nCol) );
707
+
708
+ res.add( row );
709
+ }
710
+ }finally
711
+ {
712
+ setUIWaitDB(false);
713
+ Unlock();
714
+ }
687
715
 
688
- for( ; !rows.isEnd(); rows.next() )
689
- {
690
- RubyHash row = ObjectFactory.createHash();
691
- for ( int nCol = 0; nCol < rows.getColCount(); nCol ++ )
692
- row.add( colNames[nCol], rows.getRubyValueByIdx(nCol) );
693
-
694
- res.add( row );
695
- }
696
716
  }catch(Exception e)
697
717
  {
698
718
  LOG.ERROR("execute failed.", e);
@@ -722,7 +742,7 @@ public class DBAdapter extends RubyBasic {
722
742
 
723
743
  private RubyValue rb_start_transaction() {
724
744
  try{
725
- setUnlockDB(true);
745
+ setUIWaitDB(true);
726
746
  startTransaction();
727
747
  }catch( Exception e ){
728
748
  LOG.ERROR("start_transaction failed.", e);
@@ -808,6 +828,19 @@ public class DBAdapter extends RubyBasic {
808
828
  protected RubyValue run(RubyValue receiver, RubyValue arg, RubyBlock block ){
809
829
  return ((DBAdapter)receiver).rb_destroy_table(arg);}
810
830
  });
831
+ klass.defineMethod( "is_ui_waitfordb", new RubyNoArgMethod(){
832
+ protected RubyValue run(RubyValue receiver, RubyBlock block )
833
+ {
834
+ try{
835
+ boolean bRes = ((DBAdapter)receiver).isUIWaitDB();
836
+
837
+ return ObjectFactory.createBoolean(bRes);
838
+ }catch( Exception e ){
839
+ LOG.ERROR("is_ui_waitfordb failed.", e);
840
+ throw (e instanceof RubyException ? (RubyException)e : new RubyException(e.getMessage()));
841
+ }
842
+ }
843
+ });
811
844
 
812
845
  }
813
846