rhodes 1.5.4 → 1.5.5

Sign up to get free protection for your applications and to get access to all the features.
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