Pregunta

I'm updating my Android app to use Zumero to handle data sync. Each user will get their own dbfile on the server, as well as their own internal auth account. However, I can't get zumero_internal_auth_add_user to work in Android.

I invoke the function with SQLiteDatabase.execSQL, generating SQL of the form:

SELECT zumero_internal_auth_add_user(
    '<ZUMERO URL>’,
    'test1_users',
    zumero_internal_auth_scheme('zumero_users_admin'),
    'admin',
    '<ADMIN_PWD>',
    'username',
    'pwd'
    );

This causes a SQLiteException with error code 100 (unknown error). The logs show that the operation apparently succeeded (http status code is 204: No Content), but the Zumero library did not recognize this (maybe it's only expecting 200?) and throws an exception.

06-04 23:13:42.247: V/Zumero(15442): execute for query: SELECT zumero_internal_auth_add_user(?, ?, zumero_internal_auth_scheme('zumero_users_admin'), ?, ?, ?, ?)
06-04 23:13:42.247: V/ZUMERO(15442): Network call started.
06-04 23:13:42.247: V/ZUMERO(15442): got JNI env.
06-04 23:13:42.247: V/ZUMERO(15442): Looked up java classes.
06-04 23:13:42.247: V/ZUMERO(15442): Initiating Network connection.
06-04 23:13:42.302: D/dalvikvm(15442): GC_CONCURRENT freed 132K, 2% free 9120K/9280K, paused 3ms+5ms, total 25ms
06-04 23:13:42.825: V/ZUMERO(15442): HTTP connection finished.
06-04 23:13:42.825: V/ZUMERO(15442): HTTP status code: 204.
06-04 23:13:42.825: V/ZUMERO(15442): HTTP error code: 0.
06-04 23:13:42.825: V/ZUMERO(15442): Network connection completed successfully.
06-04 23:13:42.825: W/dalvikvm(15442): threadid=13: thread exiting with uncaught exception (group=0x40b4d930)
06-04 23:13:42.833: E/AndroidRuntime(15442): FATAL EXCEPTION: AsyncTask #1
06-04 23:13:42.833: E/AndroidRuntime(15442): java.lang.RuntimeException: An error occured while executing doInBackground()
06-04 23:13:42.833: E/AndroidRuntime(15442):    at android.os.AsyncTask$3.done(AsyncTask.java:299)
06-04 23:13:42.833: E/AndroidRuntime(15442):    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
06-04 23:13:42.833: E/AndroidRuntime(15442):    at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
06-04 23:13:42.833: E/AndroidRuntime(15442):    at java.util.concurrent.FutureTask.run(FutureTask.java:239)
06-04 23:13:42.833: E/AndroidRuntime(15442):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
06-04 23:13:42.833: E/AndroidRuntime(15442):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
06-04 23:13:42.833: E/AndroidRuntime(15442):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
06-04 23:13:42.833: E/AndroidRuntime(15442):    at java.lang.Thread.run(Thread.java:856)
06-04 23:13:42.833: E/AndroidRuntime(15442): Caused by: com.zumero.sqlite.SQLiteException: error code 100: unknown error
06-04 23:18:16.575: E/AndroidRuntime(15713):    at com.zumero.sqlite.SQLiteStatement.native_execute(Native Method)
06-04 23:18:16.575: E/AndroidRuntime(15713):    at com.zumero.sqlite.SQLiteStatement.execute(SQLiteStatement.java:63)
06-04 23:18:16.575: E/AndroidRuntime(15713):    at com.zumero.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1810)
06-04 23:18:16.575: E/AndroidRuntime(15713):    at com.example.people.ZumeroBackend.addUser(ZumeroBackend.java:31)
06-04 23:18:16.575: E/AndroidRuntime(15713):    at com.example.people.PeopleProvider.insert(PeopleProvider.java:150)
06-04 23:18:16.575: E/AndroidRuntime(15713):    at android.content.ContentProvider$Transport.insert(ContentProvider.java:201)
06-04 23:18:16.575: E/AndroidRuntime(15713):    at android.content.ContentResolver.insert(ContentResolver.java:866)
06-04 23:18:16.575: E/AndroidRuntime(15713):    at com.example.people.PeopleActivity.setAccount(PeopleActivity.java:265)
06-04 23:18:16.575: E/AndroidRuntime(15713):    at com.example.people.PeopleActivity.access$3(PeopleActivity.java:262)
06-04 23:18:16.575: E/AndroidRuntime(15713):    at com.example.people.PeopleActivity$4.doInBackground(PeopleActivity.java:250)
06-04 23:18:16.575: E/AndroidRuntime(15713):    at com.example.people.PeopleActivity$4.doInBackground(PeopleActivity.java:1)
06-04 23:18:16.575: E/AndroidRuntime(15713):    at android.os.AsyncTask$2.call(AsyncTask.java:287)
06-04 23:18:16.575: E/AndroidRuntime(15713):    at java.util.concurrent.FutureTask.run(FutureTask.java:234)
06-04 23:18:16.575: E/AndroidRuntime(15713):    ... 4 more

If I try to add the same user again, the operation fails with zumero:unique_constraint_violation, confirming my suspicion that the original call succeeded. I tried running zumero_internal_auth_add_user in a SQLite shell (on Windows) and it worked fine, suggesting that the problem is specific to the Android lib. I pulled the zumero_log dbfile and found that zumero_internal_auth_add_user returns a 204 in both cases (from Android and SQLite shell).

Am I doing something wrong, or is there is a bug in the Zumero Android library?

¿Fue útil?

Solución

Here's my code which handles this use case. I never got the exact error that you saw (error code 100: unknown error). My code was tested against the android-16 version of the zumero libs, running on a Nexus 10.

public class MainActivity extends Activity {

    private File tempDBFullPath;
    private String dbName;
    private String cacheDir;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //Get the full path to the databases directory. 
        File databasesPath = this.getDatabasePath("blah").getParentFile();
        if (!databasesPath.isDirectory()) {
            //These lines make sure that the databases directory is created.
            databasesPath.mkdirs();
        }
        //Append the time to make sure that we create a new,empty database 
        //and a new internal auth db each time we run this Activity.
        this.dbName = "testdb" + new Date().getTime();

        this.tempDBFullPath = new File(databasesPath, dbName);
        this.cacheDir = this.getCacheDir().getAbsolutePath();



        //Can't do network on the main thread.
        AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {

            @Override
            protected Void doInBackground(Void... params) {
                com.zumero.sqlite.SQLiteDatabase db = com.zumero.sqlite.SQLiteDatabase.openOrCreateDatabase(MainActivity.this.tempDBFullPath, null);
                String userDB = MainActivity.this.dbName + "_users";
                boolean bExec = false;
                String serverAddress = "https://zinst12345.s.zumero.net";
                String adminPassword = "PASSWORD";

                Log.v("test", "========  creating internal auth   ==========");

                Cursor c = null;
                if (bExec) {
                    //When I run this one, I get "com.zumero.sqlite.SQLiteException: unknown error: Queries cannot be performed using execSQL(), use query() instead."
                    //That behavior matches the gingerbread android database package.
                    db.execSQL("SELECT zumero_internal_auth_create('" + serverAddress +"', '" + userDB + "', zumero_internal_auth_scheme('zumero_users_admin'), 'admin', '" + adminPassword + "', NULL,NULL,'',zumero_named_constant('acl_who_anyone'),'',zumero_named_constant('acl_who_anyone') );)");
                }
                else {
                    //This one works.
                    c = db.rawQuery("SELECT zumero_internal_auth_create(?, ?, zumero_internal_auth_scheme(?), ?, ?, NULL,NULL,'',zumero_named_constant('acl_who_anyone'),'',zumero_named_constant('acl_who_anyone') );", new String[] {serverAddress, userDB, "zumero_users_admin", "admin", adminPassword });
                    //WATCH OUT! rawQuery doesn't actually execute until the call to moveToFirst.
                    c.moveToFirst();
                }

                Log.v("test", "========  adding user   ==========");

                if (bExec) {
                    //When I run this one, I get "com.zumero.sqlite.SQLiteException: unknown error: Queries cannot be performed using execSQL(), use query() instead."
                    db.execSQL("SELECT zumero_internal_auth_add_user('" + serverAddress + "', '" + userDB + "', zumero_internal_auth_scheme('zumero_users_admin'), 'admin', '" + adminPassword + "', 'newUsername', 'newPassword');");
                }
                else {
                    //This one works.
                    c =  db.rawQuery("SELECT zumero_internal_auth_add_user(?, ?, zumero_internal_auth_scheme(?), ?, ?, ?, ?);", new String[] {serverAddress, userDB, "zumero_users_admin", "admin", adminPassword, "newUsername", "newPassword" } );
                    c.moveToFirst();
                }

                Log.v("test", "========  creating zumero acl table for this DB file.   ==========");

                c = db.rawQuery("SELECT zumero_define_acl_table('main');", null);
                c.moveToFirst();

                Log.v("test", "========  giving newUsername full permission to this DB file.   ==========");

                db.execSQL("INSERT INTO z_acl (scheme,who,tbl,op,result) VALUES (zumero_internal_auth_scheme('" + userDB + "'), zumero_named_constant('acl_who_specific_user') || 'newUsername', '', '*', zumero_named_constant('acl_result_allow'));");

                Log.v("test", "========  executing admin sync so that the server has the new acl table  ==========");

                c = db.rawQuery("SELECT zumero_sync('main', ?, ?, zumero_internal_auth_scheme(?), ?, ?, ?);", new String[] {serverAddress, dbName, "zumero_users_admin", "admin", adminPassword, MainActivity.this.cacheDir } );
                c.moveToFirst();

                Log.v("test", "========  executing sync as the new user.  ==========");

                c = db.rawQuery("SELECT zumero_sync('main', ?, ?, zumero_internal_auth_scheme(?), ?, ?, ?);", new String[] {serverAddress, dbName, userDB, "newUsername", "newPassword", MainActivity.this.cacheDir } );
                c.moveToFirst();

                db.close();

                return null;
            }
        };

        task.execute((Void)null);

        setContentView(R.layout.activity_main);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);

        return true;
    }

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top